package com.lancoo.cvas.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lancoo.cvas.arrangecourse.ArrangeCourseService;
import com.lancoo.cvas.arrangecourse.common.BinaryUtil;
import com.lancoo.cvas.arrangecourse.dataprocess.GenerateSchedulingData;
import com.lancoo.cvas.arrangecourse.entities.TeachingClassUnit;
import com.lancoo.cvas.arrangecourse.entities.TimeslotRoom;
import com.lancoo.cvas.entity.*;
import com.lancoo.cvas.exception.BizException;
import com.lancoo.cvas.exception.CapacityException;
import com.lancoo.cvas.mapper.*;
import com.lancoo.cvas.pojo.common.*;
import com.lancoo.cvas.pojo.constant.GlobalConstant;
import com.lancoo.cvas.pojo.dto.*;
import com.lancoo.cvas.pojo.vo.*;
import com.lancoo.cvas.service.*;
import com.lancoo.cvas.util.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.*;
import java.text.NumberFormat;
import java.time.LocalDate;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;


@Slf4j
@Service("scheduleService")
public class ScheduleServiceImpl extends ServiceImpl<ScheduleMapper, Schedule> implements ScheduleService {

    @Resource
    private ScheduleMapper scheduleMapper;
    @Resource
    private ScheduleConflictInfoMapper scheduleConflictInfoMapper;
    @Resource
    private TeachingClassMapper teachingClassMapper;
    @Resource
    private TeachingClassStudentMapper teachingClassStudentMapper;
    @Resource
    private TeacherService teacherService;
    @Resource
    private StudentService studentService;
    @Resource
    private TeachingClassWeekService teachingClassWeekService;
    @Resource
    private TaskInfoService taskInfoService;
    @Resource
    @Lazy
    private ArrangeCourseService arrangeCourseService;
    @Resource
    private RuleRoomProhibitMapper ruleRoomProhibitMapper;
    @Resource
    private RuleTeacherTimeMapper ruleTeacherTimeMapper;
    @Resource
    private RuleCourseProhibitMapper ruleCourseProhibitMapper;
    @Resource
    private BasicRuleService basicRuleService;
    @Resource
    private TeachingClassService teachingClassService;
    @Resource
    private RoomMapper roomMapper;

    @Resource
    private RuleClassProhibitMapper ruleClassProhibitMapper;
    @Resource
    private RuleTeachingClassProhibitMapper ruleTeachingClassProhibitMapper;
    @Resource
    private ScheduleConflictInfoService scheduleConflictInfoService;
    @Resource
    private ArrangeProcessService arrangeProcessService;
    @Resource
    private TeachingClassTeacherMapper teachingClassTeacherMapper;
    @Resource
    private ClassInfoMapper classInfoMapper;
    @Resource
    private RuleUsableService ruleUsableService;
    @Resource
    private RuleWeekDayService ruleWeekDayService;
    @Resource
    private TeacherMapper teacherMapper;
    @Resource
    private RuleTimeProhibitService ruleTimeProhibitService;
    @Resource
    private TeachingClassWeekMapper teachingClassWeekMapper;

    @Resource
    private RedisUtil redisUtil;

    @Override
    public PageInfo<TeachingClassScheduleArrangeDto> getTeachingClassCoursePage(Integer taskId, Page<TeachingClassCourseDto> page, Integer state, String gradeId, String majorId, String keyword) {
        PageInfo<TeachingClassCourseDto> pageInfo = getTeachingClassCourse(taskId, page, state, gradeId, majorId, keyword);

        List<TeachingClassCourseDto> teachingClassList = pageInfo.getList();

        Map<Long, List<TeachingClassCourseDto>> map = teachingClassList.stream()
                .collect(Collectors.groupingBy(TeachingClassCourseDto::getTeachingClassId));
        List<TeachingClassScheduleArrangeDto> res = new ArrayList<>();
        for (Long id : map.keySet()) {
            List<TeachingClassCourseDto> teachingClassCourseDtos = map.get(id);
            res.add(new TeachingClassScheduleArrangeDto()
                    .setTeachingClassId(teachingClassCourseDtos.get(0).getTeachingClassId())
                    .setTeachingClassName(teachingClassCourseDtos.get(0).getTeachingClassName())
                    .setTaskId(teachingClassCourseDtos.get(0).getTaskId())
                    .setCourseName(teachingClassCourseDtos.get(0).getCourseName())
                    .setCourseId(teachingClassCourseDtos.get(0).getCourseId())
                    .setCourseCode(teachingClassCourseDtos.get(0).getCourseCode())
                    .setTeachingClassSchedules(teachingClassCourseDtos));
        }
        IPage<TeachingClassScheduleArrangeDto> pageRes = new Page<>();
        BeanUtil.copyProperties(pageInfo, pageRes);
        pageRes.setRecords(res);
        return PagingUtil.formatPageResult(pageRes);
    }


    @Override
    public PageInfo<TeachingClassCourseDto> getTeachingClassCourse(Integer taskId, Page<TeachingClassCourseDto> page, Integer state, String gradeId, String majorId, String keyword) {
        //获取排课教学班信息
        IPage<TeachingClassCourseDto> teachingClassPage = teachingClassMapper.getCourseTeachingClassForArrange(page, taskId, state, gradeId, majorId, keyword);
        List<TeachingClassCourseDto> teachingClassList = teachingClassPage.getRecords();
        if (CollUtil.isNotEmpty(teachingClassList)) {
            List<Long> teachingClassIds = teachingClassList.stream().map(TeachingClassCourseDto::getTeachingClassId).collect(Collectors.toList());
            //补充教师信息
            Map<Long, List<Teacher>> teachingClassToTeacher = teacherService.getTeacherByTeachingClassIds(teachingClassIds)
                    .stream().collect(Collectors.groupingBy(Teacher::getTeachingClassId));

            //学生人数
            Map<Long, Integer> studentNumMap = teachingClassStudentMapper.getStudentNumber(teachingClassIds)
                    .stream().collect(Collectors.toMap(TeachingClassCourseDto::getTeachingClassId, TeachingClassCourseDto::getStudentNumber));
            //冲突信息
            List<ScheduleConflictInfo> cnoflictList = scheduleConflictInfoMapper.getWithRoomName(
                    teachingClassIds, Deleted.NOT.getCode());
            fillConflict(cnoflictList);
            Map<Long, List<ScheduleConflictInfo>> cnoflictMap = cnoflictList.stream().collect(Collectors.groupingBy(ScheduleConflictInfo::getTeachingClassId));

            //补充规则信息
            Map<Long, List<RuleTeachingClassProhibit>> ruleMap = ruleTeachingClassProhibitMapper.
                    getAllProhibitTimeCode(taskId,Deleted.NOT.getCode(),1)
                    .stream().collect(Collectors.groupingBy(RuleTeachingClassProhibit::getTeachingClassId));

            //课表信息
            List<ScheduleDto> scheduleDtoList = scheduleMapper.getAllScheduleByTeachingClassIds(null, teachingClassIds);
            scheduleDtoList.forEach(o -> o.setRoomTypeName(StrUtil.isEmpty(GlobalConstant.roomTypeMap2.get(o.getRoomType())) ? "" : GlobalConstant.roomTypeMap2.get(o.getRoomType())));
            Map<Long, List<ScheduleDto>> scheduleMap = scheduleDtoList.stream().collect(Collectors.groupingBy(ScheduleDto::getTeachingClassId));

            teachingClassList.forEach(a -> {
                //多教师版本
                List<Teacher> teachers = teachingClassToTeacher.getOrDefault(a.getTeachingClassId(),new ArrayList<>());
                teachers = teachers.stream().filter(t -> Objects.equals(t.getTeacherType(), a.getHourType())).collect(Collectors.toList());
                a.setTeachers(teachers);

                //规则
                List<RuleTeachingClassProhibit> rules = ruleMap.getOrDefault(a.getTeachingClassId(),new ArrayList<>());
                rules = rules.stream().filter(r -> Objects.equals(r.getHourType(), a.getHourType())).collect(Collectors.toList());
                List<String> ruleTimes = rules.stream().map(RuleTeachingClassProhibit::getTimeCode).distinct().collect(Collectors.toList());


                //学生人数
                a.setStudentNumber(studentNumMap.getOrDefault(a.getTeachingClassId(), 0));
                //冲突
                if (CollUtil.isNotEmpty(cnoflictMap.get(a.getTeachingClassId()))) {
                    a.setConflicts(cnoflictMap.get(a.getTeachingClassId()).stream()
                            .filter(o -> o.getHourType().equals(a.getHourType()))
                            .collect(Collectors.toList()));
                }
                //课表
                if (CollUtil.isNotEmpty(scheduleMap.get(a.getTeachingClassId()))) {
                    List<ScheduleDto> schedules = scheduleMap.get(a.getTeachingClassId()).stream()
                            .filter(o -> o.getHourType().equals(a.getHourType()))
                            .collect(Collectors.toList());
                    List<String> scheduleTimes = schedules.stream().map(ScheduleDto::getTimeCode).collect(Collectors.toList());
                    int scheduleSize = schedules.size();
                    //处理课表顺序
                    List<ScheduleConflictInfo> conflicts = a.getConflicts();
                    if (CollUtil.isNotEmpty(conflicts)){
                        schedules.forEach(s -> {

//                            if (a.getState() == ScheduleState.UNSUITABLE.getCode()){
//                                if (scheduleSize >= ruleTimes.size()){
//                                    List<String> unSuitTimes = CollUtil.subtractToList(ruleTimes, scheduleTimes);
//                                    if (unSuitTimes.contains(s.getTimeCode())){
//                                        s.setSuit(-1);
//                                    }
//                                }else {
//                                    List<String> unSuitTimes = CollUtil.subtractToList(scheduleTimes, ruleTimes);
//                                    if (unSuitTimes.contains(s.getTimeCode())){
//                                        s.setSuit(-1);
//                                    }
//                                }
//                            }

                            if (conflicts.stream().anyMatch(c -> Objects.equals(s.getTimeCode(), c.getTimeCode())
                                    && Objects.equals(s.getRoomId(), c.getRoomId()))){
                                s.setOrder(3);
                            }
                            if (StrUtil.isEmpty(s.getTimeCode())){
                                s.setOrder(4);
                            }
                        });
                    }
                    //设置教学班课表
                    a.setSchedules(schedules.stream()
                            .sorted(Comparator.comparing(ScheduleDto::getOrder).reversed())
                            .collect(Collectors.toList()));
                    //处理未满足规则的教学班
                    if (a.getState() == ScheduleState.UNSUITABLE.getCode() && CollUtil.isNotEmpty(ruleTimes)){
                        //课表比规则多的  找出没有满足的规则
                        if (scheduleSize >= ruleTimes.size()){
                            List<String> unSuitTimes = CollUtil.subtractToList(ruleTimes, scheduleTimes);
                            rules = rules.stream().filter(r -> unSuitTimes.contains(r.getTimeCode())).collect(Collectors.toList());
                        }else {
                            //规则比课表多的 找出没有满足的规则
//                            List<String> unSuitTimes = CollUtil.subtractToList(ruleTimes, scheduleTimes);
//                            if (ruleTimes.size() - unSuitTimes.size() < scheduleTimes.size()){
                                rules = rules.stream().filter(r -> !scheduleTimes.contains(r.getTimeCode())).collect(Collectors.toList());
//                            }
                        }
                        //未满的规则 构造前端显示的内容
                        if (CollUtil.isNotEmpty(rules)) {
                            StringBuilder msg = new StringBuilder();
//                            List<UnSuitRuleVo> unSuitRules = new ArrayList<>();
                            //根据类型分组
                            Map<Integer, List<RuleTeachingClassProhibit>> map = rules.stream().collect(Collectors.groupingBy(RuleTeachingClassProhibit::getType));
                            for (Integer type : map.keySet()) {
                                //每一个类型的规则
                                List<RuleTeachingClassProhibit> typeRules = map.getOrDefault(type, new ArrayList<>());
                                if (CollUtil.isNotEmpty(typeRules)) {
                                    if (FixType.getByCode(type) == null) {
                                        continue;
                                    }
                                    //将timecode转变成 周几第几节
                                    String timeCodeString = typeRules.stream()
                                            .map(o -> TimeCodeUtil.convert(o.getTimeCode()))
                                            .collect(Collectors.joining(" "));
                                    msg.append(FixType.getByCode(type).getMsg().replaceAll("固排", "规则: "));
                                    msg.append(timeCodeString);
                                    msg.append(",");

//                                    unSuitRules.add(new UnSuitRuleVo()
//                                    .setRuleType(FixType.getByCode(type).getMsg().replaceAll("固排", "规则"))
//                                    .setRules(typeRules));
                                }
                            }
                            //设置教学班为满足的规则
                            a.setRules("未满足：" + msg.toString().substring(0,msg.toString().length()-1));
                        }
                    }
                }
            });
        }
        teachingClassPage.setRecords(teachingClassList);
        return PagingUtil.formatPageResult(teachingClassPage);
    }

    @Override
    public PageInfo<TeachingClassSegmentDto> getTeachingClassSegmentPage(Integer taskId, Page<TeachingClassSegmentDto> page, String gradeId, String majorId, String type, String keyword) {
        IPage<TeachingClassSegmentDto> teachingClassPage = teachingClassMapper.getSegmentTeachingClassForArrange(page, taskId, gradeId, majorId, type, keyword);
        List<TeachingClassSegmentDto> teachingClassList = teachingClassPage.getRecords();
        if (CollUtil.isNotEmpty(teachingClassList)) {
            List<Long> teachingClassIds = teachingClassList.stream().map(TeachingClassSegmentDto::getTeachingClassId).collect(Collectors.toList());
            //学生人数
            Map<Long, Integer> studentNumMap = teachingClassStudentMapper.getStudentNumber(teachingClassIds)
                    .stream().collect(Collectors.toMap(TeachingClassCourseDto::getTeachingClassId, TeachingClassCourseDto::getStudentNumber));
            //补充教师信息
            Map<Long, List<Teacher>> teachingClassToTeacher = teacherService.getTeacherByTeachingClassIds(teachingClassIds)
                    .stream().collect(Collectors.groupingBy(Teacher::getTeachingClassId));
            //填充周次数据
            List<TeachingClassWeek> teachingClassWeekList = teachingClassWeekService.list(new LambdaQueryWrapper<TeachingClassWeek>().in(TeachingClassWeek::getTeachingClassId, teachingClassIds));
            Map<Long, List<TeachingClassWeek>> weekMap = teachingClassWeekList.stream().collect(Collectors.groupingBy(TeachingClassWeek::getTeachingClassId));

            //班级信息
            Map<Long, List<ClassInfo>> classMap = classInfoMapper.getClassName(taskId).stream().collect(Collectors.groupingBy(ClassInfo::getId));


            teachingClassList.forEach(a -> {
                a.setTeachers(teachingClassToTeacher.getOrDefault(a.getTeachingClassId(),new ArrayList<>()));
                //周次
                a.setCourseWeeks(weekMap.get(a.getTeachingClassId()));
                //学生人数
                a.setStudentNumber(studentNumMap.getOrDefault(a.getTeachingClassId(), 0));

                //班级
                List<ClassInfo> list = new ArrayList<>();
                for (String s : a.getClassId().split(",")) {
                    list.addAll(classMap.get(Long.parseLong(s)));
                }
                a.setClassInfos(list);
            });
        }
        teachingClassPage.setRecords(teachingClassList);
        return PagingUtil.formatPageResult(teachingClassPage);
    }

    /**
     * @param currentPage:
     * @param pageSize:
     * @param taskId:
     * @param weeks:
     * @param timeCodes:
     * @param roomId:
     * @param teachingClass:
     * @Description: 获取调整场地节次 列表
     * @Author: liufeng
     * @Date: 2023/12/12 15:13
     * @return:
     */
    @Override
    public PageInfo<VenueSessionVo> getVenueSession(Integer currentPage, Integer pageSize, Integer taskId, String weeks,
                                                    String timeCodes, Integer buildingId, Long roomId, String keyword, ArrangeTeachingClassDto teachingClass) throws CapacityException {
        List<VenueSessionVo> venueSessionVos = new ArrayList<>();
        TaskInfo taskInfo = taskInfoService.getById(taskId);
        //可用的 场地节次
        LinkedList<TimeslotRoom> timeslotRooms = arrangeCourseService.getAvailableTimeslotRoomList(taskInfo.getSchoolId(), taskInfo.getTerm(),
                taskId, Integer.parseInt(weeks, 2) == 0 ? null : weeks, timeCodes, buildingId, roomId, keyword, teachingClass);

        if (CollUtil.isEmpty(timeslotRooms)) {
            return new PageInfo<>();
        }

        RuleUsable capacityCheck = ruleUsableService.getByCode(taskId,20);
        if (capacityCheck != null && "b".equals(capacityCheck.getOption())){
            int preSize = timeslotRooms.size();

            timeslotRooms = timeslotRooms.stream()
                    .filter(timeslotRoom -> timeslotRoom.getCapacity() >= teachingClass.getStudentNumber())
                    .collect(Collectors.toCollection(LinkedList::new));

            int postSize = timeslotRooms.size();
            if(preSize != 0 && postSize == 0){
                throw new CapacityException(999,"教学班人数(" + teachingClass.getStudentNumber()
                        + ")大于所有可用教室的容量");
            }
        }

        // 返回连上的场地节次
        List<TimeslotRoom[]> consecutiveSessions = findConsecutiveSessions(timeslotRooms, teachingClass.getConnectSection());
        PageInfo<TimeslotRoom[]> pages = PagingUtil.getPages(currentPage, pageSize, consecutiveSessions);
        pages.getList().forEach(consecutiveSession -> {
            //对分组的数据取周次与运算
            String resultWeek = Arrays.stream(consecutiveSession)
                    .map(TimeslotRoom::getWeeks)
                    .reduce(BinaryUtil::binaryAnd)
                    .orElse("");
            //可用节次
            String resultSession = "{}[{}节]";
            String week = TimeCodeUtil.DAY_NAME.get(TimeCodeUtil.DAY_CODE.indexOf(consecutiveSession[0].getTimeslotCode().substring(0, 2)));
            List<Integer> sectionList = Arrays.stream(consecutiveSession).map(a -> Integer.valueOf(a.getTimeslotCode().substring(2))).distinct().sorted().collect(Collectors.toList());
            venueSessionVos.add(new VenueSessionVo()
                    .setRoomId(consecutiveSession[0].getRoomId())
                    .setRoomName(consecutiveSession[0].getRoomName())
                    .setWeeks(resultWeek)
                    .setSession(StrUtil.format(resultSession, week, StrUtil.join("、", sectionList)))
                    .setBuildingId(consecutiveSession[0].getBuildingId())
                    .setBuildingName(consecutiveSession[0].getBuildingName())
                    .setTimeCode(Arrays.stream(consecutiveSession).map(TimeslotRoom::getTimeslotCode).collect(Collectors.toList())));
        });

        //适配  有可用的可以拆课表  没有可用的不拆
        boolean canSub = CollUtil.isNotEmpty(timeslotRooms);

        return new PageInfo<VenueSessionVo>()
                .setCurrentPage(pages.getCurrentPage())
                .setPageSize(pages.getPageSize())
                .setTotal(pages.getTotal())
                .setPages(pages.getPages())
                .setList(venueSessionVos)
                .setCanSub(canSub);
    }

    /**
     * 根据连上节次获取 连上组合
     *
     * @param timeslotRoomList
     * @param consecutiveCount
     * @return
     */
    public List<TimeslotRoom[]> findConsecutiveSessions(List<TimeslotRoom> timeslotRoomList, int consecutiveCount) {
        List<TimeslotRoom[]> consecutiveSessions = new ArrayList<>();
        //根据room分组
        Map<Long, List<TimeslotRoom>> groupSessions = timeslotRoomList.stream()
                .collect(Collectors.groupingBy(TimeslotRoom::getRoomId));

        for (List<TimeslotRoom> timeslotRooms : groupSessions.values()) {
            // 根据 timeCode 进行排序
            timeslotRooms.sort(Comparator.comparing(TimeslotRoom::getTimeslotCode));
            //遍历每一个节次
            for (int i = 0; i < timeslotRooms.size() - consecutiveCount + 1; i++) {
                //选择连着的连上节次判断是否符合要求
                boolean isConsecutive = IntStream.range(i + 1, i + consecutiveCount)
                        .allMatch(j -> Integer.parseInt(timeslotRooms.get(j).getTimeslotCode()) - Integer.parseInt(timeslotRooms.get(j - 1).getTimeslotCode()) == 1);
                //添加上午下午判断
                boolean isPeriodType = IntStream.range(i + 1, i + consecutiveCount)
                        .allMatch(j -> timeslotRooms.get(j).getPeriodType().equals(timeslotRooms.get(j - 1).getPeriodType()));

                if (isConsecutive && isPeriodType) {
                    consecutiveSessions.add(timeslotRooms.subList(i, i + consecutiveCount).toArray(new TimeslotRoom[0]));
                }
            }
        }
        return consecutiveSessions;
    }

    /**
     * @param taskId:
     * @param schoolId:
     * @param term:
     * @param campusId:
     * @Description: 获取教室禁排
     * @Author: liufeng
     * @Date: 2023/12/12 15:26
     * @return:
     */
    @Override
    public List<ArrangeRoomRuleDto> getArrangeRoomProhibit(Integer taskId, String schoolId, String term, String campusId) {
        List<ArrangeRoomRuleDto> arrangeRoomRule = ruleRoomProhibitMapper.getArrangeRoomRuleByTaskId(taskId, schoolId, term, campusId, Deleted.NOT.getCode());
        return arrangeRoomRule;
    }

    /**
     * @param taskId:
     * @param schoolId:
     * @param term:
     * @Description: 获取教师禁排
     * @Author: liufeng
     * @Date: 2023/12/12 15:33
     * @return:
     */
    @Override
    public List<ArrangeTeacherRuleDto> getArrangeTeacherTime(Integer taskId, String schoolId, String term) {
        List<ArrangeTeacherRuleDto> arrangeTeacherRule = ruleTeacherTimeMapper.getArrangeTeacherRuleByTaskId(taskId, schoolId, term, Deleted.NOT.getCode());
        return arrangeTeacherRule;
    }

    @Override
    public List<ArrangeCourseRuleDto> getArrangeCourseProhibit(Integer taskId) {
        List<ArrangeCourseRuleDto> arrangeCourseRule = ruleCourseProhibitMapper.getArrangeCourseRuleByTaskId(taskId);
        return arrangeCourseRule;
    }

    @Override
    public List<ArrangeClassRuleDto> getArrangeClassProhibit(Integer taskId) {
        List<ArrangeClassRuleDto> arrangeClassRule = ruleClassProhibitMapper.getArrangeCourseRuleByTaskId(taskId, Deleted.NOT.getCode());
        return arrangeClassRule;
    }

    @Override
    public List<ArrangeTeachingClassRuleDto> getArrangeTeachingClassProhibit(Integer taskId) {
        List<ArrangeTeachingClassRuleDto> arrangeTeachingClassRule = ruleTeachingClassProhibitMapper.getArrangeTeachingCourseRuleByTaskId(taskId, Deleted.NOT.getCode());
        return arrangeTeachingClassRule;
    }

    @Override
    public List<ArrangePeriod> getArrangeTimeCode(Integer taskId, String schoolId, String term) {
        List<ArrangePeriod> periodCode = new ArrayList<>();
        List<RuleWeekDay> weekDays = basicRuleService.getWeekDays(taskId, schoolId, term);

        //禁排
        Set<String> timeProhibit;
        RuleUsable timeRule = ruleUsableService.getByCode(taskId, 12);
        if ("b".equals(timeRule.getOption())) {
            timeProhibit = basicRuleService.getTimeProhibit(taskId, schoolId, term)
                    .stream().map(RuleTimeProhibit::getTimeCode).collect(Collectors.toSet());
        } else {
            timeProhibit = new HashSet<>();
        }

        weekDays.forEach(weekDay -> {
            weekDay.getPeriodSchemes().forEach(periodScheme -> {
                //第几节
                Integer period = periodScheme.getPeriod();
                //学时code
                String code = weekDay.getWeekDayCode() + String.format("%02d", period);
                //是否属于禁排
                Integer isProhibit = timeProhibit.contains(code) ? 1 : 0;
                //名字格式修改
                String name = "周" + weekDay.getWeekDayCode() + "第" + period + "节";
                periodCode.add(ArrangePeriod.builder().timeCode(code).codeName(name)
                        .periodType(periodScheme.getPeriodType()).period(period)
                        .isProhibit(isProhibit).build());

            });

        });
        return periodCode;
    }

    /**
     * @param taskId:
     * @param campusId:
     * @param isLocked:
     * @param roomType:
     * @Description: 获取本任务已经锁定的课表。以及本学期其他任务课表  包含教学班的教室id、学时信息
     * @Author: liufeng
     * @Date: 2023/12/12 16:32
     * @return:
     */
    @Override
    public List<ArrangeScheduleDto> getLockSchedule(Integer taskId, String campusId, Integer isLocked, Integer roomType) {
        List<ArrangeScheduleDto> scheduleLocked = new ArrayList<>();
        //本学期其他任务课表
        TaskInfo taskInfo = taskInfoService.getById(taskId);
        List<TaskInfo> taskInfos = taskInfoService.lambdaQuery().eq(TaskInfo::getSchoolId, taskInfo.getSchoolId()).eq(TaskInfo::getTerm, taskInfo.getTerm()).list();
        List<Integer> taskIds = taskInfos.stream().map(TaskInfo::getTaskId).filter(o -> !o.equals(taskId)).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(taskIds)) {
            scheduleLocked = scheduleMapper.getScheduleLockedByIds(taskIds, campusId, isLocked, roomType);
        }
        scheduleLocked.addAll(scheduleMapper.getScheduleLocked(taskId, campusId, isLocked, roomType));

        if (CollUtil.isEmpty(scheduleLocked)) {
            return scheduleLocked;
        }
        //补充教师信息
        List<Long> teachingClassIds = scheduleLocked.stream().map(ArrangeScheduleDto::getTeachingClassId).collect(Collectors.toList());
        Map<Long, List<Teacher>> teachingClassToTeacher = teacherService.getTeacherByTeachingClassIds(teachingClassIds)
                .stream().collect(Collectors.groupingBy(Teacher::getTeachingClassId));
        scheduleLocked.forEach(o -> {
            //补充codeName
            o.setCodeName(TimeCodeUtil.convert(o.getTimeCode()));
            //补充教师信息 单独添加，因为教师业务以后可能会变化
            List<Teacher> teachers = teachingClassToTeacher.getOrDefault(o.getTeachingClassId(),new ArrayList<>());
            //多教师版本
            teachers = teachers.stream().filter(t -> Objects.equals(t.getTeacherType(), o.getHourType())).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(teachers)) {
                String teacherIds = StrUtil.join(",", teachers.stream().map(Teacher::getTeacherId).collect(Collectors.toList()));
                o.setTeacherIds(teacherIds);
            }
        });
        return scheduleLocked;
    }


    @Override
    public List<ArrangeScheduleDto> getScheduleListByTeachingClassIds(Integer taskId, String campusId, List<Long> tcIds) {
        List<ArrangeScheduleDto> scheduleLocked = new ArrayList<>();
        scheduleLocked.addAll(scheduleMapper.getScheduleListByTeachingClassIds(taskId, campusId, tcIds));

        if (CollUtil.isEmpty(scheduleLocked)) {
            return scheduleLocked;
        }
        return scheduleLocked;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<ScheduleDto> updateVenueSession(List<Schedule> startSchedule, List<Schedule> stopSchedule, Long teachingClassId, Integer hourType) {
        List<Schedule> addSchedule = new ArrayList<>();
        List<Schedule> updateSchedule = new ArrayList<>();
        List<Schedule> deleteSchedule = new ArrayList<>();
        //原来的场地节次 要么更新 都为0时删除。并且每个课表信息应该一致
        if (Integer.parseInt(startSchedule.get(0).getWeek(), 2) == 0) {
            deleteSchedule.addAll(startSchedule);
        } else {
            updateSchedule.addAll(startSchedule);
        }
        //新的场地节次 要么新增 要么更新.当存在场地节次一致时，则是更新
        List<Schedule> scheduleList = this.lambdaQuery().eq(Schedule::getTeachingClassId, teachingClassId)
                .eq(Schedule::getHourType, hourType).list();
        scheduleList.stream().forEach(schedule -> {
            if (StrUtil.isNotBlank(schedule.getTimeCode()) && ObjUtil.isNotNull(schedule.getRoomId())) {
                stopSchedule.forEach(stop -> {
                    //场地节次一致时， 更新周次信息
                    if (schedule.getRoomId().equals(stop.getRoomId()) && schedule.getTimeCode().equals(stop.getTimeCode()) && schedule.getHourType().equals(stop.getHourType())) {
                        stop.setId(schedule.getId());
                        stop.setWeek(BinaryUtil.binaryOR(schedule.getWeek(), stop.getWeek()));
                        updateSchedule.add(stop);
                    }
                });
            }
        });
        addSchedule = stopSchedule.stream().filter(schedule -> schedule.getId() == null).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(addSchedule)) {
            Optional<Schedule> first = scheduleList.stream()
                    .filter(o -> Objects.equals(o.getId(), startSchedule.get(0).getId()))
                    .findFirst();
            if (first.isPresent()){
                addSchedule.forEach(o -> o.setReserve(first.get().getReserve()));
            }
            this.saveBatch(addSchedule);
        }
        if (CollUtil.isNotEmpty(updateSchedule)) {
            this.updateBatchById(updateSchedule);
        }
        if (CollUtil.isNotEmpty(deleteSchedule)) {
            this.removeByIds(deleteSchedule);
        }
        return scheduleMapper.getAllScheduleByTeachingClassIdAndHourType(teachingClassId, hourType);
    }

    @Override
    public void updateScheduleState(List<ArrangeTeachingClassUpdate> arrangeTeachingClassUpdates) {
        //todo 可以根据排课状态批量更新
        List<TeachingClass> teachingClassList = BeanUtil.copyToList(arrangeTeachingClassUpdates, TeachingClass.class);
        teachingClassService.updateBatchById(teachingClassList);
    }


    @Override
    public List<ScheduleConflictInfo> autoArrangement(Integer taskId) {
        arrangeCourseService.algService(taskId);
        //返回冲突
        List<ScheduleConflictInfo> scheduleConflictInfos = scheduleConflictInfoMapper.selectList(new LambdaQueryWrapper<ScheduleConflictInfo>().eq(ScheduleConflictInfo::getTaskId, taskId));
        log.info("排课完成,taskId={}，记录冲突，冲突数：{}",taskId,scheduleConflictInfos.size());
        fillConflict(scheduleConflictInfos);
        return scheduleConflictInfos;
    }


    /**
     * @param taskId:
     * @param schoolId:
     * @param term:
     * @Description: 统计需要新建的教室
     * @Author: liufeng
     * @Date: 2024/1/9 11:37
     * @return:
     */
    @Override
    public RoomRequire requireRoom(Integer taskId, String schoolId, String term, Integer requireRoomType) {
        Integer count = scheduleMapper.getCount(taskId);
        RoomRequire res = new RoomRequire();
        if (count == 0) {
            return res;
        } else {
            //获取未排课数据
            List<TeachingClassWeek> teachingClassWeekList = teachingClassWeekService.getUnRanage(taskId, requireRoomType,Deleted.NOT.getCode());
            if (CollUtil.isEmpty(teachingClassWeekList)) {
                return res;
            }
            //根据roomType分组
            Map<Integer, List<TeachingClassWeek>> type = teachingClassWeekList.stream()
                    .collect(Collectors.groupingBy(TeachingClassWeek::getRoomType));
            //获取课时方案
            List<ArrangePeriod> timeCodeList = this.getArrangeTimeCode(taskId, schoolId, term).stream().filter(o -> o.getIsProhibit() == 0)
                    .collect(Collectors.toList());
            //课时禁排
            Long prohibit = ruleTimeProhibitService.lambdaQuery()
                    .eq(RuleTimeProhibit::getTaskId, taskId)
                    .eq(RuleTimeProhibit::getDeleted, Deleted.NOT.getCode()).count();
            //所有教学班禁排
            List<RuleTeachingClassProhibit> allProhibitTimeCode = ruleTeachingClassProhibitMapper.getAllProhibitTimeCode(taskId, Deleted.NOT.getCode(), 2);
            //所有教学班已经排课的数据
            List<ScheduleDto> scheduleByTeachingClassIds = scheduleMapper.getScheduleByTeachingClassIds(taskId, teachingClassWeekList.stream().map(TeachingClassWeek::getTeachingClassId).distinct().collect(Collectors.toList()), null);
            Map<Integer, List<ScheduleDto>> scheduleMap = new HashMap<>();
            if (CollUtil.isNotEmpty(scheduleByTeachingClassIds)) {
                scheduleMap = scheduleByTeachingClassIds.stream().collect(Collectors.groupingBy(ScheduleDto::getRoomType));
            }
            //分组处理
            for (Integer roomType : type.keySet()) {
                //该roomType下所有学时
                int sum = type.get(roomType).stream().map(TeachingClassWeek::getWeekNum).mapToInt(x -> x).sum();
                //除去已经排课的
                List<ScheduleDto> scheduleList = scheduleMap.get(roomType);
                sum = sum - (CollUtil.isNotEmpty(scheduleList) ? scheduleList.size() : 0);
                if (sum != 0) {
                    //公共禁排课时
                    List<Long> tcIds = type.get(roomType).stream().map(TeachingClassWeek::getTeachingClassId).distinct().collect(Collectors.toList());
                    List<String> timeCodes = allProhibitTimeCode.stream()
                            .filter(o -> tcIds.contains(o.getTeachingClassId()))
                            .map(RuleTeachingClassProhibit::getTimeCode).collect(Collectors.toList());

                    //总共的课时 - 禁排的课时 - 教学班的禁排
                    int useable = timeCodeList.size() - prohibit.intValue() - timeCodes.size();
                    //需要的课时 / 可用的 （+1）
                    int require = sum % (useable) == 0 ? sum / (useable) : sum / (useable) + 1;
                    res.getRooms().put(GlobalConstant.roomTypeMap2.get(roomType), require);
                }
            }
            res.setShow(res.getRooms().size() != 0);
        }

        return res;
    }

    @Override
    public StatisticsArrange getPublishStatisticsArrange(Integer taskId, String schoolId) {
        StatisticsArrange res = new StatisticsArrange();


        //查询所有教学班信息  排除环节
        List<TeachingClass> teachingClassList = teachingClassService.lambdaQuery()
                .eq(TeachingClass::getTaskId, taskId)
                .eq(TeachingClass::getFlag, 1)
                .eq(TeachingClass::getDeleted, Deleted.NOT.getCode())
                .in(TeachingClass::getIsEnable, Arrays.asList(IsEnable.ENABLE.getCode(), 6))
                .list();

        //查询冲突信息
        List<ScheduleConflictInfo> conflictInfoList = scheduleConflictInfoService.lambdaQuery()
                .eq(ScheduleConflictInfo::getTaskId, taskId)
                .eq(ScheduleConflictInfo::getDeleted, Deleted.NOT.getCode()).list();


        List<TeachingClassWeek> weeks = new ArrayList<>();
        if (CollUtil.isNotEmpty(teachingClassList)) {
            List<Long> teachingClassIds = teachingClassList.stream()
                    .map(TeachingClass::getTeachingClassId).collect(Collectors.toList());

            //查询教学班周次信息
            weeks = teachingClassWeekMapper.getByTeachingClassIds(teachingClassIds,Deleted.NOT.getCode());
            if (weeks.size() == 0) {
                return res;
            }
            //week根据排课状态分组
            Map<Integer, List<TeachingClassWeek>> scheduleStateMap = weeks.stream()
                    .collect(Collectors.groupingBy(TeachingClassWeek::getScheduleState));

            //查询课表
            List<Schedule> schedules = scheduleMapper.selectBuTaskId(taskId, Deleted.NOT.getCode());
            //没有排课  直接返回
            if (schedules.stream().filter(o -> StrUtil.isNotEmpty(o.getTimeCode())).collect(Collectors.toList()).size() == 0) {
                return res.setUnArrangeNum(scheduleStateMap.get(ScheduleState.UNARRANGE.getCode())
                        .stream().mapToInt(TeachingClassWeek::getWeekNum).sum());
            }


            //排课节次  不满足规则在高级 禁排规则设置
            for (Integer state : scheduleStateMap.keySet()) {
                //不满足规则的
                if (ScheduleState.UNARRANGE.getCode() == state) {
                    List<TeachingClassWeek> teachingClassWeeks = scheduleStateMap.get(state);
                    //总课时
                    long sum = teachingClassWeeks.stream().mapToInt(TeachingClassWeek::getWeekNum).sum();
                    //已排课时
                    long arranged = 0;
                    for (TeachingClassWeek teachingClassWeek : teachingClassWeeks) {
                        arranged += schedules.stream().filter(o -> Objects.equals(o.getTeachingClassId(), teachingClassWeek.getTeachingClassId())
                                && Objects.equals(o.getHourType(), teachingClassWeek.getHourType())
                                && StrUtil.isNotEmpty(o.getTimeCode())).count();
                    }
                    //正常课时
                    res.setNormalNum(res.getNormalNum() + arranged);

                    //冲突 冲突中没排的
                    long conflicts = 0;
                    long cons = 0;
                    List<TeachingClassWeek> conflictTeachingClassWeeks = scheduleStateMap.get(ScheduleState.CONFLICT.getCode());
                    if (CollUtil.isNotEmpty(conflictTeachingClassWeeks)) {
                        //冲突的总的
                        conflicts = conflictTeachingClassWeeks.stream().mapToInt(TeachingClassWeek::getWeekNum).sum();

                        for (TeachingClassWeek teachingClassWeek : conflictTeachingClassWeeks) {
                            //冲突的已经排了的
                            cons += schedules.stream().filter(o -> Objects.equals(o.getTeachingClassId(), teachingClassWeek.getTeachingClassId())
                                    && Objects.equals(o.getHourType(), teachingClassWeek.getHourType())
                                    && StrUtil.isNotEmpty(o.getTimeCode())).count();
                        }
                    }

                    //未满足的其中没排的
                    long unsuitArranged = 0;
                    long sunsuitAll = 0;
                    List<TeachingClassWeek> unsuitTeachingClassWeeks = scheduleStateMap.get(ScheduleState.UNSUITABLE.getCode());
                    if (CollUtil.isNotEmpty(unsuitTeachingClassWeeks)) {
                        //未满足规则总的
                        sunsuitAll = unsuitTeachingClassWeeks.stream().mapToInt(TeachingClassWeek::getWeekNum).sum();
                        for (TeachingClassWeek teachingClassWeek : unsuitTeachingClassWeeks) {
                            //未满足已经排了的
                            unsuitArranged += schedules.stream().filter(o -> Objects.equals(o.getTeachingClassId(), teachingClassWeek.getTeachingClassId())
                                    && Objects.equals(o.getHourType(), teachingClassWeek.getHourType())
                                    && StrUtil.isNotEmpty(o.getTimeCode())).count();
                        }
                    }

                    res.setUnArrangeNum(sum - arranged + (conflicts - cons) + (sunsuitAll - unsuitArranged));
                    continue;
                }
                if (ScheduleState.NORMAL.getCode() == state) {
                    List<TeachingClassWeek> teachingClassWeeks = scheduleStateMap.get(state);
                    //正常的总共的
                    long sum = teachingClassWeeks.stream().mapToInt(TeachingClassWeek::getWeekNum).sum();

                    //未满足的其中满足的一部分
                    long sum2 = 0;
                    List<TeachingClassWeek> unsuitTeachingClassWeeks = scheduleStateMap.get(ScheduleState.UNSUITABLE.getCode());
                    if (CollUtil.isNotEmpty(unsuitTeachingClassWeeks)) {
//                        sum2 = unsuitTeachingClassWeeks.stream().mapToInt(TeachingClassWeek::getWeekNum).sum();
                        for (TeachingClassWeek teachingClassWeek : unsuitTeachingClassWeeks) {
                            //未满足的其中满足的一部分
                            sum2 += schedules.stream().filter(o -> Objects.equals(o.getTeachingClassId(), teachingClassWeek.getTeachingClassId())
                                    && Objects.equals(o.getHourType(), teachingClassWeek.getHourType())
                                    && StrUtil.isNotEmpty(o.getTimeCode())).count();
                        }
                    }

                    //未排  会有一部分排了
                    long unRanges = 0;
                    List<TeachingClassWeek> unRangeTeachingClassWeeks = scheduleStateMap.get(ScheduleState.UNARRANGE.getCode());
                    if (CollUtil.isNotEmpty(unRangeTeachingClassWeeks)){
                        for (TeachingClassWeek teachingClassWeek : unRangeTeachingClassWeeks) {
                            unRanges += schedules.stream().filter(o -> Objects.equals(o.getTeachingClassId(), teachingClassWeek.getTeachingClassId())
                                    && Objects.equals(o.getHourType(), teachingClassWeek.getHourType())
                                    && StrUtil.isNotEmpty(o.getTimeCode())).count();
                        }
                    }

                    //冲突中正常的在冲突中处理

                    res.setNormalNum(res.getNormalNum() + sum + sum2 + unRanges);

                    continue;
                }
                if (ScheduleState.CONFLICT.getCode() == state) {
                    List<TeachingClassWeek> teachingClassWeeks = scheduleStateMap.get(state);
                    List<ScheduleConflictInfo> list = scheduleConflictInfoMapper.getDistinctConflictByWeeks(teachingClassWeeks);
                    //冲突的
                    res.setConflictNum(list.size());

                    //冲突 冲突中正常的
//                    long conflicts = 0;
                    List<TeachingClassWeek> conflictTeachingClassWeeks = scheduleStateMap.get(ScheduleState.CONFLICT.getCode());
//                    if (CollUtil.isNotEmpty(conflictTeachingClassWeeks)) {
//                        conflicts = conflictTeachingClassWeeks.stream().mapToInt(TeachingClassWeek::getWeekNum).sum();
//                    }

                    long cons = 0;
                    for (TeachingClassWeek teachingClassWeek : conflictTeachingClassWeeks) {
                        //冲突总的
                        cons += schedules.stream().filter(o -> Objects.equals(o.getTeachingClassId(), teachingClassWeek.getTeachingClassId())
                                && Objects.equals(o.getHourType(), teachingClassWeek.getHourType())
                                && StrUtil.isNotEmpty(o.getTimeCode())).count();
                    }
                    res.setNormalNum(res.getNormalNum() + (cons - list.size()));
                    continue;
                }

                if (ScheduleState.UNSUITABLE.getCode() == state){
                    //未满足的其中满足的一部分
                    long sum = 0;
                    List<TeachingClassWeek> unsuitTeachingClassWeeks = scheduleStateMap.get(ScheduleState.UNSUITABLE.getCode());
                    if (CollUtil.isNotEmpty(unsuitTeachingClassWeeks)) {
//                        sum2 = unsuitTeachingClassWeeks.stream().mapToInt(TeachingClassWeek::getWeekNum).sum();
                        for (TeachingClassWeek teachingClassWeek : unsuitTeachingClassWeeks) {
                            sum += schedules.stream().filter(o -> Objects.equals(o.getTeachingClassId(), teachingClassWeek.getTeachingClassId())
                                    && Objects.equals(o.getHourType(), teachingClassWeek.getHourType())
                                    && StrUtil.isNotEmpty(o.getTimeCode())).count();
                        }
                    }
                    res.setNormalNum(res.getNormalNum() + sum);
                }
            }


//            res.setNormalNum(scheduleStateMap.get(ScheduleState.NORMAL.getCode()) == null ? 0 : scheduleStateMap.get(ScheduleState.NORMAL.getCode()).size())
//                    .setConflictNum(scheduleStateMap.get(ScheduleState.CONFLICT.getCode()) == null ? 0 : scheduleStateMap.get(ScheduleState.CONFLICT.getCode()).size())
//                    .setUnArrangeNum(scheduleStateMap.get(ScheduleState.UNARRANGE.getCode()) == null ? 0 : scheduleStateMap.get(ScheduleState.UNARRANGE.getCode()).size())
//                    .setUnsuitableNum(scheduleStateMap.get(ScheduleState.UNSUITABLE.getCode()) == null ? 0 : scheduleStateMap.get(ScheduleState.UNSUITABLE.getCode()).size());
        }

        //冲突节次
        if (CollUtil.isNotEmpty(conflictInfoList)) {
            //冲突类型分组
            Map<Integer, List<ScheduleConflictInfo>> conflictMap = conflictInfoList.stream()
                    .collect(Collectors.groupingBy(ScheduleConflictInfo::getConflictType));

            res.setTeacherConflict(conflictMap.get(ConflictType.Teacher.getCode()) == null ? 0 : conflictMap.get(ConflictType.Teacher.getCode()).size())
                    .setStudentConflict(conflictMap.get(ConflictType.Student.getCode()) == null ? 0 : conflictMap.get(ConflictType.Student.getCode()).size())
                    .setRoomConflict(conflictMap.get(ConflictType.Room.getCode()) == null ? 0 : conflictMap.get(ConflictType.Room.getCode()).size());
        }

        //获取教学班的课表课时
        List<ScheduleDto> scheduleDtoList = teachingClassMapper.getSchedule(taskId);
        if (CollUtil.isNotEmpty(scheduleDtoList)) {

            //课表根据教学班分组
            Map<Long, List<ScheduleDto>> map = scheduleDtoList.stream()
                    .collect(Collectors.groupingBy(ScheduleDto::getTeachingClassId));
//            List<Long> teachingClassIds = scheduleDtoList.stream()
//                    .map(ScheduleDto::getTeachingClassId).distinct().collect(Collectors.toList());
            //获取不是正常的教学班
            List<Long> teachingClassIds = weeks.stream().filter(o -> o.getScheduleState() != 1)
                    .map(TeachingClassWeek::getTeachingClassId).distinct().collect(Collectors.toList());

            //获取规则信息
            List<RuleUsable> rules = ruleUsableService.getByTask(taskId);

            Map<String, Object> temp = new HashMap<>();

            //高级规则
            temp.put("sum", 0);
            //计算多少没有满足高级规则
            String fixRule = getFixRule(taskId, map, teachingClassIds, rules, temp);
            res.setFixRule(fixRule);
            int sum1 = (int) temp.get("sum");

            //禁排规则
            temp.put("sum", 0);
            //计算多少没有满足禁排规则
            String prohibitRule = getProhibitRule(taskId, schoolId, scheduleDtoList, teachingClassIds, rules, temp);
            res.setProhibitRule(prohibitRule);
            int sum2 = (int) temp.get("sum");


            //未满足的
            res.setUnsuitableNum(sum1 + sum2);
            //正常未满足  减去真正不满足的
            res.setNormalNum(res.getNormalNum() - (sum1 + sum2));

            //基础规则是否开启
            if ("a".equals(rules.stream().filter(o -> o.getCode() == 19)
                    .collect(Collectors.toList()).get(0).getOption())) {
                return res.setBaseRule("100.00");
            } else {
                //计算基础规则满足率
                ArrangeProcess arrangeProcess = arrangeProcessService.lambdaQuery()
                        .eq(ArrangeProcess::getTaskId, taskId)
                        .orderByDesc(ArrangeProcess::getId).one();
                res.setBaseRule(getPercent(arrangeProcess.getNormal(),
                        arrangeProcess.getNormal() + arrangeProcess.getUnsuitBase()));
            }

        }


        return res;
    }


    @Override
    public StatisticsArrange getPublishStatisticsArrangeV2(Integer taskId, String schoolId) {
        StatisticsArrange res = new StatisticsArrange();


        //查询所有教学班信息  排除环节
        List<TeachingClass> teachingClassList = teachingClassService.lambdaQuery()
                .eq(TeachingClass::getTaskId, taskId)
                .eq(TeachingClass::getFlag, 1)
                .eq(TeachingClass::getDeleted, Deleted.NOT.getCode())
                .in(TeachingClass::getIsEnable, Arrays.asList(IsEnable.ENABLE.getCode(), 6))
                .list();

        //查询冲突信息
        List<ScheduleConflictInfo> conflictInfos = scheduleConflictInfoService.lambdaQuery()
                .eq(ScheduleConflictInfo::getTaskId, taskId)
                .eq(ScheduleConflictInfo::getDeleted, Deleted.NOT.getCode()).list();
        List<ScheduleConflictInfo> conflictInfoList = new ArrayList<>();
        conflictInfos.forEach(o -> {
            if (!conflictInfoList.contains(o)){
                conflictInfoList.add(o);
            }
        });

        List<TeachingClassWeek> weeks = new ArrayList<>();
        if (CollUtil.isNotEmpty(teachingClassList)) {
            List<Long> teachingClassIds = teachingClassList.stream()
                    .map(TeachingClass::getTeachingClassId).collect(Collectors.toList());

            //查询教学班周次信息
            weeks = teachingClassWeekMapper.getByTeachingClassIds(teachingClassIds,Deleted.NOT.getCode());
            if (weeks.size() == 0) {
                return res;
            }
            //week根据排课状态分组
            Map<Integer, List<TeachingClassWeek>> scheduleStateMap = weeks.stream()
                    .collect(Collectors.groupingBy(TeachingClassWeek::getScheduleState));

            //查询课表
            List<Schedule> schedules = scheduleMapper.selectBuTaskId(taskId, Deleted.NOT.getCode());
            //没有排课  直接返回
            if (schedules.stream().filter(o -> StrUtil.isNotEmpty(o.getTimeCode())).collect(Collectors.toList()).size() == 0) {
                return res.setUnArrangeNum(scheduleStateMap.get(ScheduleState.UNARRANGE.getCode())
                        .stream().mapToInt(TeachingClassWeek::getWeekNum).sum());
            }


            //排课节次  不满足规则在高级 禁排规则设置
            for (Integer state : scheduleStateMap.keySet()) {
                //没排完的
                if (ScheduleState.UNARRANGE.getCode() == state) {
                    List<TeachingClassWeek> teachingClassWeeks = scheduleStateMap.get(state);
                    //总课时
                    long sum = teachingClassWeeks.stream().mapToInt(TeachingClassWeek::getWeekNum).sum();
                    //已排课时
                    long arranged = 0;
                    for (TeachingClassWeek teachingClassWeek : teachingClassWeeks) {
                        arranged += schedules.stream().filter(o -> Objects.equals(o.getTeachingClassId(), teachingClassWeek.getTeachingClassId())
                                && Objects.equals(o.getHourType(), teachingClassWeek.getHourType())
                                && StrUtil.isNotEmpty(o.getTimeCode())).count();
                    }
                    //正常课时
                    res.setNormalNum(res.getNormalNum() + arranged);

                    //冲突 冲突中没排的
                    long conflicts = 0;
                    long cons = 0;
                    List<TeachingClassWeek> conflictTeachingClassWeeks = scheduleStateMap.get(ScheduleState.CONFLICT.getCode());
                    if (CollUtil.isNotEmpty(conflictTeachingClassWeeks)) {
                        //冲突的总的
                        conflicts = conflictTeachingClassWeeks.stream().mapToInt(TeachingClassWeek::getWeekNum).sum();

                        for (TeachingClassWeek teachingClassWeek : conflictTeachingClassWeeks) {
                            //冲突的已经排了的
                            cons += schedules.stream().filter(o -> Objects.equals(o.getTeachingClassId(), teachingClassWeek.getTeachingClassId())
                                    && Objects.equals(o.getHourType(), teachingClassWeek.getHourType())
                                    && StrUtil.isNotEmpty(o.getTimeCode())).count();
                        }
                    }

                    //未满足的其中没排的
                    long unsuitArranged = 0;
                    long sunsuitAll = 0;
                    List<TeachingClassWeek> unsuitTeachingClassWeeks = scheduleStateMap.get(ScheduleState.UNSUITABLE.getCode());
                    if (CollUtil.isNotEmpty(unsuitTeachingClassWeeks)) {
                        //未满足规则总的
                        sunsuitAll = unsuitTeachingClassWeeks.stream().mapToInt(TeachingClassWeek::getWeekNum).sum();
                        for (TeachingClassWeek teachingClassWeek : unsuitTeachingClassWeeks) {
                            //未满足已经排了的
                            unsuitArranged += schedules.stream().filter(o -> Objects.equals(o.getTeachingClassId(), teachingClassWeek.getTeachingClassId())
                                    && Objects.equals(o.getHourType(), teachingClassWeek.getHourType())
                                    && StrUtil.isNotEmpty(o.getTimeCode())).count();
                        }
                    }

                    res.setUnArrangeNum(sum - arranged + (conflicts - cons) + (sunsuitAll - unsuitArranged));
                    continue;
                }
                if (ScheduleState.NORMAL.getCode() == state) {
                    List<TeachingClassWeek> teachingClassWeeks = scheduleStateMap.get(state);
                    //正常的总共的
                    long sum = teachingClassWeeks.stream().mapToInt(TeachingClassWeek::getWeekNum).sum();

                    //未满足的其中满足的一部分


                    //未排  会有一部分排了


                    //冲突中正常的在冲突中处理

                    res.setNormalNum(res.getNormalNum() + sum);

                    continue;
                }
                if (ScheduleState.CONFLICT.getCode() == state) {
                   //冲突的
                    res.setConflictNum(conflictInfoList.size());

                    //冲突 冲突中正常的
                    List<TeachingClassWeek> conflictTeachingClassWeeks = scheduleStateMap.get(ScheduleState.CONFLICT.getCode());


                    long cons = 0;
                    for (TeachingClassWeek teachingClassWeek : conflictTeachingClassWeeks) {
                        //冲突总的
                        cons += schedules.stream().filter(o -> Objects.equals(o.getTeachingClassId(), teachingClassWeek.getTeachingClassId())
                                && Objects.equals(o.getHourType(), teachingClassWeek.getHourType())
                                && StrUtil.isNotEmpty(o.getTimeCode())).count();
                    }
                    res.setNormalNum(res.getNormalNum() + cons);
                    continue;
                }

                if (ScheduleState.UNSUITABLE.getCode() == state){
                    //未满足的其中满足的一部分
                    long sum = 0;
                    List<TeachingClassWeek> unsuitTeachingClassWeeks = scheduleStateMap.get(ScheduleState.UNSUITABLE.getCode());
                    if (CollUtil.isNotEmpty(unsuitTeachingClassWeeks)) {
                        for (TeachingClassWeek teachingClassWeek : unsuitTeachingClassWeeks) {
                            sum += schedules.stream().filter(o -> Objects.equals(o.getTeachingClassId(), teachingClassWeek.getTeachingClassId())
                                    && Objects.equals(o.getHourType(), teachingClassWeek.getHourType())
                                    && StrUtil.isNotEmpty(o.getTimeCode())).count();
                        }
                    }
                    res.setNormalNum(res.getNormalNum() + sum);
                }
            }

        }

        //冲突节次
        if (CollUtil.isNotEmpty(conflictInfoList)) {

            res.setConflictNum(conflictInfoList.size());
            res.setNormalNum(res.getNormalNum() - conflictInfoList.size());
            //冲突类型分组
            Map<Integer, List<ScheduleConflictInfo>> conflictMap = conflictInfoList.stream()
                    .collect(Collectors.groupingBy(ScheduleConflictInfo::getConflictType));

            res.setTeacherConflict(conflictMap.get(ConflictType.Teacher.getCode()) == null ? 0 : conflictMap.get(ConflictType.Teacher.getCode()).size())
                    .setStudentConflict(conflictMap.get(ConflictType.Student.getCode()) == null ? 0 : conflictMap.get(ConflictType.Student.getCode()).size())
                    .setRoomConflict(conflictMap.get(ConflictType.Room.getCode()) == null ? 0 : conflictMap.get(ConflictType.Room.getCode()).size());
        }

        //获取教学班的课表课时
        List<ScheduleDto> scheduleDtoList = teachingClassMapper.getSchedule(taskId);
        if (CollUtil.isNotEmpty(scheduleDtoList)) {

            //课表根据教学班分组
            Map<Long, List<ScheduleDto>> map = scheduleDtoList.stream()
                    .collect(Collectors.groupingBy(ScheduleDto::getTeachingClassId));
            //获取不是正常的教学班
            List<Long> teachingClassIds = weeks.stream().filter(o -> o.getScheduleState() != 1)
                    .map(TeachingClassWeek::getTeachingClassId).distinct().collect(Collectors.toList());

            //获取规则信息
            List<RuleUsable> rules = ruleUsableService.getByTask(taskId);

            Map<String, Object> temp = new HashMap<>();

            //高级规则
            temp.put("sum", 0);
            //计算多少没有满足高级规则
            String fixRule = getFixRule(taskId, map, teachingClassIds, rules, temp);
            res.setFixRule(fixRule);
            int sum1 = (int) temp.get("sum");

            //禁排规则
            temp.put("sum", 0);
            //计算多少没有满足禁排规则
            String prohibitRule = getProhibitRule(taskId, schoolId, scheduleDtoList, teachingClassIds, rules, temp);
            res.setProhibitRule(prohibitRule);
            int sum2 = (int) temp.get("sum");


            //未满足的
            res.setUnsuitableNum(sum1 + sum2);
            //正常未满足  减去真正不满足的
            res.setNormalNum(res.getNormalNum() - (sum1 + sum2));

            //基础规则是否开启
            if ("a".equals(rules.stream().filter(o -> o.getCode() == 19)
                    .collect(Collectors.toList()).get(0).getOption())) {
                return res.setBaseRule("100.00");
            } else {
                //计算基础规则满足率
                ArrangeProcess arrangeProcess = arrangeProcessService.lambdaQuery()
                        .eq(ArrangeProcess::getTaskId, taskId)
                        .orderByDesc(ArrangeProcess::getId).one();
                res.setBaseRule(getPercent(arrangeProcess.getNormal(),
                        arrangeProcess.getNormal() + arrangeProcess.getUnsuitBase()));
            }

        }


        return res;
    }

    private String getFixRule(Integer taskId, Map<Long, List<ScheduleDto>> map, List<Long> teachingClassIds, List<RuleUsable> rules, Map<String, Object> temp) {
        List<String> options = rules.stream().filter(o -> o.getCode() == 17
                || o.getCode() == 16
                || o.getCode() == 15
                || o.getCode() == 14
                || o.getCode() == 18).map(RuleUsable::getOption).collect(Collectors.toList());
        if (CollUtil.isEmpty(teachingClassIds) || options.size() == 1 && "a".equals(options.get(0))) {
            return "100.00";
        }

        int sum = (int) temp.get("sum");

        //获取教学班固排信息
        List<RuleTeachingClassProhibit> fixByTeachingClassId = ruleTeachingClassProhibitMapper
                .getFixByTeachingClassId(taskId, teachingClassIds, 1, Deleted.NOT.getCode());

        //判断启用规则
        if ("a".equals(rules.stream().filter(o -> o.getCode() == 14)
                .collect(Collectors.toList()).get(0).getOption())) {
            fixByTeachingClassId = fixByTeachingClassId.stream().filter(o ->
                    o.getType() != FixType.Room.getCode()).collect(Collectors.toList());
        }
        if ("a".equals(rules.stream().filter(o -> o.getCode() == 15)
                .collect(Collectors.toList()).get(0).getOption())) {
            fixByTeachingClassId = fixByTeachingClassId.stream().filter(o ->
                    o.getType() != FixType.Teacher.getCode()).collect(Collectors.toList());
        }
        if ("a".equals(rules.stream().filter(o -> o.getCode() == 16)
                .collect(Collectors.toList()).get(0).getOption())) {
            fixByTeachingClassId = fixByTeachingClassId.stream().filter(o ->
                    o.getType() != FixType.Class.getCode()).collect(Collectors.toList());
        }
        if ("a".equals(rules.stream().filter(o -> o.getCode() == 17)
                .collect(Collectors.toList()).get(0).getOption())) {
            fixByTeachingClassId = fixByTeachingClassId.stream().filter(o ->
                    o.getType() != FixType.TeachingClass.getCode()).collect(Collectors.toList());
        }
        if ("a".equals(rules.stream().filter(o -> o.getCode() == 18)
                .collect(Collectors.toList()).get(0).getOption())) {
            fixByTeachingClassId = fixByTeachingClassId.stream().filter(o ->
                    o.getType() != FixType.Course.getCode()).collect(Collectors.toList());
        }


//        HashSet<Long> unsuit = new HashSet<>();

        int total = 0;

        for (Long id : map.keySet()) {
            //当前固排课时
            List<RuleTeachingClassProhibit> fix = fixByTeachingClassId.stream()
                    .filter(o -> o.getTeachingClassId().equals(id)).collect(Collectors.toList());

            List<ScheduleDto> scheduleDtos = map.get(id);
            total += scheduleDtos.size();

            if (CollUtil.isNotEmpty(fix)) {
                Map<Integer, List<ScheduleDto>> hourTypeMap = scheduleDtos.stream()
                        .collect(Collectors.groupingBy(ScheduleDto::getHourType));
                for (Integer type : hourTypeMap.keySet()) {
                    List<RuleTeachingClassProhibit> rule = fixByTeachingClassId.stream()
                            .filter(o -> o.getTeachingClassId().equals(id)
                                    && Objects.equals(o.getHourType(), type))
                            .collect(Collectors.toList());
                    if (CollUtil.isNotEmpty(rule)) {
                        //获取教学班的课表课时
                        List<ScheduleDto> curSchedules = hourTypeMap.get(type);
                        Map<String, List<ScheduleDto>> group = curSchedules.stream().collect(Collectors.groupingBy(ScheduleDto::getTimeGroup));
                        int tempUnSuit = 0;
                        for (String key : group.keySet()) {
                            List<ScheduleDto> list = group.get(key);
                            //课表课时
                            List<String> timeCodes = list.stream().map(ScheduleDto::getTimeCode).collect(Collectors.toList());
                            //当前固排课时
                            List<String> fixTimeCodes = rule.stream().map(RuleTeachingClassProhibit::getTimeCode).collect(Collectors.toList());

                            if (rule.size()==0){
                                continue;
                            }
                            List<String> suit = new ArrayList<>(CollUtil.intersection(timeCodes, fixTimeCodes));
                            //没有满足的规则剩余数量
                            //删除满足过的规则
                            rule = rule.stream().filter(o -> !suit.contains(o.getTimeCode())).collect(Collectors.toList());

                            //不满足规则的
                            int size = suit.size();
                            if (size == 0){
                                sum += timeCodes.size();
                                //暂时没有满
                                tempUnSuit++;
                            }
                        }

                        /*
                        暂时没有满的数量大于 rule 剩余规则数量 那肯定有一部分满足过  迭代的时候顺序不对
                        如果小于  那么就是不满足规则
                         */
                        sum = sum - (tempUnSuit > rule.size() ? (tempUnSuit - rule.size()) : 0);


//                        List<String> timeCodes = hourTypeMap.get(type).stream().map(ScheduleDto::getTimeCode).collect(Collectors.toList());
//                        //当前固排课时
//                        List<String> fixTimeCodes = rule.stream().map(RuleTeachingClassProhibit::getTimeCode).collect(Collectors.toList());
//
//                        int size = CollUtil.intersection(timeCodes, fixTimeCodes).size();
//                        int un = timeCodes.size() - size;
//                        sum += un;
                    }
                }
//                //获取教学班的课表课时
//                List<String> timeCodes = map.get(id).stream().map(ScheduleDto::getTimeCode).collect(Collectors.toList());
//                //当前固排课时
//                List<String> fixTimeCodes = fix.stream().map(RuleTeachingClassProhibit::getTimeCode).collect(Collectors.toList());
//
//                int size = CollUtil.intersection(timeCodes, fixTimeCodes).size();
//                int un = fixTimeCodes.size() - size;
//                sum += un;


//                if (!timeCodes.containsAll(fixTimeCodes)) {
//                    unsuit.add(id);
//                }
            }
        }
        temp.put("sum", sum);
        return getPercent(total - sum, total);
    }

    private String getProhibitRule(Integer taskId, String schoolId, List<ScheduleDto> scheduleDtoList, List<Long> teachingClassIds, List<RuleUsable> rules, Map<String, Object> temp) {
//        HashSet<Long> unsuit = new HashSet<>();
        if (CollUtil.isEmpty(teachingClassIds) || CollUtil.isEmpty(scheduleDtoList)) {
            return "100.00";
        }

        int sum = (int) temp.get("sum");

        //禁排规则
        FixDto fixDto = new FixDto();
        for (ScheduleDto scheduleDto : scheduleDtoList) {
            fixDto.setTeachingClassId(scheduleDto.getTeachingClassId())
                    //多教师版本
                    .setTeacherIds(String.valueOf(scheduleDto.getTeacherIds()))
                    .setRoomId(scheduleDto.getRoomId())
                    .setClassId(scheduleDto.getToClass())
                    .setSchoolId(schoolId)
                    .setCourseId(scheduleDto.getCourseId())
                    .setTimeCode(scheduleDto.getTimeCode())
                    .setHourType(scheduleDto.getHourType());

            FixVo fixVo = basicRuleService.checkProhibitConflictWithRule(taskId, Collections.singletonList(fixDto), rules);
            if (!fixVo.getSuccess()) {
                sum += 1;
//                unsuit.add(scheduleDto.getTeachingClassId());
            }
        }
        temp.put("sum", sum);
        return getPercent(teachingClassIds.size() - sum, teachingClassIds.size());
    }

    private String getPercent(int x, int y) {
        double d1 = x * 1.0;
        double d2 = y * 1.0;
        NumberFormat percentInstance = NumberFormat.getPercentInstance();
        // 设置保留几位小数，这里设置的是保留两位小数
        percentInstance.setMinimumFractionDigits(2);
        String format = percentInstance.format(d1 / d2);
        return format.substring(0, format.length() - 1);
    }

    /**
     * 填充冲突信息 将id转换为字符串填到对应冲突字符串后面
     *
     * @param scheduleConflictInfos
     */
    @Override
    public void fillConflict(List<ScheduleConflictInfo> scheduleConflictInfos) {
        //填充冲突字符串
        List<TeachingClass> teachingClassList = new ArrayList<>();
        List<Room> roomList = new ArrayList<>();
        List<Teacher> teacherList = new ArrayList<>();
        List<Student> studentList = new ArrayList<>();
        Map<Integer, List<ScheduleConflictInfo>> scheduleConflictInfoMap = scheduleConflictInfos.stream().collect(Collectors.groupingBy(ScheduleConflictInfo::getConflictType));
        List<Long> clashUnitIds = new ArrayList<>();
        //获取冲突类型 对应实体类
        if (CollUtil.isNotEmpty(scheduleConflictInfoMap.get(ConflictType.TeachingClass.getCode()))) {
            clashUnitIds = scheduleConflictInfoMap.get(ConflictType.TeachingClass.getCode()).stream().map(ScheduleConflictInfo::getClashUnit).collect(Collectors.toList());
            if (!clashUnitIds.isEmpty()) {
                teachingClassList = teachingClassService.listByIds(clashUnitIds);
            }
        }
        if (CollUtil.isNotEmpty(scheduleConflictInfoMap.get(ConflictType.Room.getCode()))) {
            clashUnitIds = scheduleConflictInfoMap.get(ConflictType.Room.getCode()).stream().map(ScheduleConflictInfo::getClashUnit).collect(Collectors.toList());
            if (!clashUnitIds.isEmpty()) {
                roomList = roomMapper.selectBatchIds(clashUnitIds);
            }
        }
        if (CollUtil.isNotEmpty(scheduleConflictInfoMap.get(ConflictType.Teacher.getCode()))) {
            clashUnitIds = scheduleConflictInfoMap.get(ConflictType.Teacher.getCode()).stream().map(ScheduleConflictInfo::getClashUnit).collect(Collectors.toList());
            if (!clashUnitIds.isEmpty()) {
                teacherList = teacherService.listByIds(clashUnitIds);
            }
        }
        if (CollUtil.isNotEmpty(scheduleConflictInfoMap.get(ConflictType.Student.getCode()))) {
            clashUnitIds = scheduleConflictInfoMap.get(ConflictType.Student.getCode()).stream().map(ScheduleConflictInfo::getClashUnit).collect(Collectors.toList());
            if (!clashUnitIds.isEmpty()) {
                studentList = studentService.listByIds(clashUnitIds);
            }
        }

        //字符串填充
        for (ScheduleConflictInfo scheduleConflictInfo : scheduleConflictInfos) {
            if (scheduleConflictInfo.getConflictType() == ConflictType.TeachingClass.getCode()) {
                Optional<TeachingClass> teachingClass = teachingClassList.stream().filter(b -> b.getTeachingClassId().equals(scheduleConflictInfo.getClashUnit())).findFirst();
                teachingClass.ifPresent(aClass -> scheduleConflictInfo.setConflictReason(scheduleConflictInfo.getConflictReason() + aClass.getTeachingClassName()));
            }
            if (scheduleConflictInfo.getConflictType() == ConflictType.Room.getCode()) {
                Optional<Room> room = roomList.stream().filter(b -> b.getRoomId().equals(scheduleConflictInfo.getClashUnit())).findFirst();
                room.ifPresent(value -> scheduleConflictInfo.setConflictReason(scheduleConflictInfo.getConflictReason() + value.getRoomName()));
            }
            if (scheduleConflictInfo.getConflictType() == ConflictType.Teacher.getCode()) {
                Optional<Teacher> teacher = teacherList.stream().filter(b -> b.getTeacherId().equals(scheduleConflictInfo.getClashUnit())).findFirst();
                teacher.ifPresent(value -> scheduleConflictInfo.setConflictReason(value.getTeacherName() + scheduleConflictInfo.getConflictReason()));
            }
            if (scheduleConflictInfo.getConflictType() == ConflictType.Student.getCode()) {
                Optional<Student> student = studentList.stream().filter(b -> b.getStudentId().equals(scheduleConflictInfo.getClashUnit())).findFirst();
                student.ifPresent(value -> scheduleConflictInfo.setConflictReason(scheduleConflictInfo.getConflictReason() + value.getStudentName() + " 学号" + value.getBaseStudentId()));
            }
        }
    }


    @Override
    public List<ArrangeTeachingClassDto> getTeachingClassDate(Integer taskId, String campusId) {
        List<ArrangeTeachingClassDto> allTeachingClass = new ArrayList<>();
        //获取课程教学班
        List<ArrangeTeachingClassDto> teachingClassCourse = teachingClassMapper.getCourseArrangeTeachingClassDto(taskId, campusId);
        allTeachingClass.addAll(teachingClassCourse);
        //补充教师信息
        List<Long> teachingClassIds = allTeachingClass.stream().map(ArrangeTeachingClassDto::getTeachingClassId).collect(Collectors.toList());
        Map<Long, List<Teacher>> teachingClassToTeacher = teacherService.getTeacherByTeachingClassIds(teachingClassIds)
                .stream().collect(Collectors.groupingBy(Teacher::getTeachingClassId));
        allTeachingClass.forEach(o -> {
            //补充教师信息 单独添加，因为教师业务以后可能会变化
            List<Teacher> teachers = teachingClassToTeacher.getOrDefault(o.getTeachingClassId(),new ArrayList<>());
            if (CollUtil.isNotEmpty(teachers)) {
                //多教师版本
                teachers = teachers.stream().filter(t -> Objects.equals(o.getHourType(), t.getTeacherType())).collect(Collectors.toList());
                String teacherIds = StrUtil.join(",", teachers.stream().map(Teacher::getTeacherId).collect(Collectors.toList()));
                String teacherNames = StrUtil.join(",", teachers.stream().map(Teacher::getTeacherName).collect(Collectors.toList()));
                o.setTeacherIds(teacherIds);
                o.setTeacherNames(teacherNames);
            }

            //选课教学班初始人数为0
            if (o.getTeachingClassType() == 1){
                o.setStudentNumber(o.getSelectedMax());
            }
        });
        return allTeachingClass;
    }

    @Override
    public void addBathSchedule(Integer taskId, List<Schedule> schedules) {
        TaskInfo taskInfo = taskInfoService.getById(taskId);
        //获取本学期任务
        List<Integer> taskIds = taskInfoService.lambdaQuery().eq(TaskInfo::getSchoolId, taskInfo.getSchoolId()).eq(TaskInfo::getTerm, taskInfo.getTerm()).list()
                .stream().map(TaskInfo::getTaskId).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(taskIds)) {
            scheduleMapper.delete(new LambdaUpdateWrapper<Schedule>().in(Schedule::getTaskId, taskId));
        }
        //批量插入课表，大数据批量插入
        Consumer<List<Schedule>> scheduleConsumer = o -> scheduleMapper.addBatch(o);
        BatchInsert.batchSplitInsert(schedules, scheduleConsumer);
    }

    @Override
    public void addBatchScheduleConflict(Integer taskId, List<ScheduleConflictInfo> scheduleConflicts, List<Long> roomIds) {
        //需要先清除原来的冲突
//        if (CollUtil.isNotEmpty(roomIds)) {
//            scheduleConflictInfoMapper.delete(new LambdaUpdateWrapper<ScheduleConflictInfo>().eq(ScheduleConflictInfo::getTaskId, taskId).in(ScheduleConflictInfo::getRoomId, roomIds));
//        }
        scheduleConflictInfoMapper.delete(new LambdaUpdateWrapper<ScheduleConflictInfo>().eq(ScheduleConflictInfo::getTaskId, taskId));
        //批量插入课表，大数据批量插入
        Consumer<List<ScheduleConflictInfo>> scheduleConflictConsumer = o -> scheduleConflictInfoMapper.addBatch(o);
        BatchInsert.batchSplitInsert(scheduleConflicts, scheduleConflictConsumer);
    }

    /**
     * @param teachingClassId:
     * @param hourType:
     * @Description: 获取教学班冲突
     * @Author: liufeng
     * @Date: 2023/12/18 15:46
     * @return:
     */
    @Override
    public List<ScheduleConflictInfo> getScheduleConflictInfo(Long teachingClassId, Integer hourType) {
        List<ScheduleConflictInfo> list = scheduleConflictInfoService.lambdaQuery()
                .eq(ScheduleConflictInfo::getTeachingClassId, teachingClassId)
                .eq(ScheduleConflictInfo::getHourType, hourType)
                .eq(ScheduleConflictInfo::getDeleted, Deleted.NOT.getCode()).list();
        fillConflict(list);
        return list;
    }


    /**
     * @param isLocked:
     * @param locks:
     * @Description: 修改教学班锁定状态
     * @Author: liufeng
     * @Date: 2023/12/18 15:56
     * @return:
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateLock(Integer taskId, Integer isLocked, LockDto locks) {
        if (locks.getTeachingClassId() == null || locks.getHourType() == null) {
            return false;
        }
        Long count = arrangeProcessService.lambdaQuery().eq(ArrangeProcess::getTaskId, taskId).count();
        if (count == 0) {
            throw new BizException(EnumResultCode.FAIL.getCode(), "未进行自动排课，禁止锁定");
        }

        teachingClassWeekService.updateLocks(isLocked, locks);

        //处理单双拆班问题
        //要锁全部锁，解锁全部解锁
        TeachingClass teachingClass = teachingClassService.getById(locks.getTeachingClassId());
        //必须是单双拆班
        if (teachingClass != null && teachingClass.getSubId() != null && teachingClass.getSubId() == 0){
            String uniqueShiftSign = teachingClass.getUniqueShiftSign();
            List<Long> ids = teachingClassService.lambdaQuery()
                    .eq(TeachingClass::getTaskId, taskId)
                    .eq(TeachingClass::getSubId, 0)
                    .eq(TeachingClass::getUniqueShiftSign, uniqueShiftSign)
                    .eq(TeachingClass::getDeleted, Deleted.NOT.getCode())
                    .list().stream().map(TeachingClass::getTeachingClassId)
                    .collect(Collectors.toList());

            teachingClassWeekService.lambdaUpdate()
                    .in(TeachingClassWeek::getTeachingClassId,ids)
                    .set(TeachingClassWeek::getIsLocked,isLocked)
                    .update();
        }

        return true;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean allNormalLocal(Integer taskId) {
        Long count = arrangeProcessService.lambdaQuery().eq(ArrangeProcess::getTaskId, taskId).count();
        if (count == 0) {
            throw new BizException(EnumResultCode.FAIL.getCode(), "未进行自动排课，禁止锁定");
        }
        //查询所有教学班
        List<TeachingClass> teachingClassList = teachingClassService.lambdaQuery()
                .eq(TeachingClass::getTaskId, taskId)
                .eq(TeachingClass::getDeleted, Deleted.NOT.getCode())
                .list();
        List<Long> teachingClassIds = teachingClassList.stream().map(TeachingClass::getTeachingClassId)
                .distinct().collect(Collectors.toList());
        if (CollUtil.isEmpty(teachingClassIds)) {
            return false;
        }
        //查询排课正常的教学班week
        List<TeachingClassWeek> weekList = teachingClassWeekService.lambdaQuery()
                .in(TeachingClassWeek::getTeachingClassId, teachingClassIds)
                .eq(TeachingClassWeek::getScheduleState, ScheduleState.NORMAL.getCode())
                .list();
        //更新锁定状态
        boolean update = teachingClassWeekService.lambdaUpdate()
                .in(TeachingClassWeek::getTeachingClassId, teachingClassIds)
                .eq(TeachingClassWeek::getScheduleState, ScheduleState.NORMAL.getCode())
                .set(TeachingClassWeek::getIsLocked, 2).update();
        if (update){
            arrangeProcessService.lambdaUpdate().eq(ArrangeProcess::getTaskId,taskId)
                    .set(ArrangeProcess::getIsLocked,2).update();
        }

        //单双拆班问题
        //修改的教学班
        List<Long> tcIds = weekList.stream().map(TeachingClassWeek::getTeachingClassId)
                .distinct().collect(Collectors.toList());
        teachingClassList = teachingClassList.stream()
                .filter(o -> tcIds.contains(o.getTeachingClassId()))
                .collect(Collectors.toList());
        //筛选单双班
        List<TeachingClass> subTeachingClassList = teachingClassList.stream()
                .filter(o -> o.getSubId() != null && o.getSubId() == 0)
                .collect(Collectors.toList());
        if (CollUtil.isNotEmpty(subTeachingClassList)){
            //获取分组信息
            List<String> groups = subTeachingClassList.stream().map(TeachingClass::getUniqueShiftSign)
                    .distinct()
                    .collect(Collectors.toList());
            if (CollUtil.isNotEmpty(groups)){
                //根据分组获取教学班
                List<Long> ids = teachingClassService.lambdaQuery()
                        .eq(TeachingClass::getTaskId, taskId)
                        .eq(TeachingClass::getSubId, 0)
                        .in(TeachingClass::getUniqueShiftSign, groups)
                        .eq(TeachingClass::getDeleted, Deleted.NOT.getCode())
                        .list().stream().map(TeachingClass::getTeachingClassId)
                        .distinct().collect(Collectors.toList());

                //更新拆班锁定状态
                teachingClassWeekService.lambdaUpdate()
                        .in(TeachingClassWeek::getTeachingClassId,ids)
                        .set(TeachingClassWeek::getIsLocked,2)
                        .update();
            }
        }

        return update;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean unlockedNormal(Integer taskId) {
        Long count = arrangeProcessService.lambdaQuery().eq(ArrangeProcess::getTaskId, taskId).count();
        if (count == 0) {
            throw new BizException(EnumResultCode.FAIL.getCode(), "未进行自动排课");
        }

        List<TeachingClass> teachingClassList = teachingClassService.lambdaQuery()
                .eq(TeachingClass::getTaskId, taskId)
                .eq(TeachingClass::getDeleted, Deleted.NOT.getCode())
                .list();
        List<Long> teachingClassIds = teachingClassService.lambdaQuery()
                .eq(TeachingClass::getTaskId, taskId)
                .eq(TeachingClass::getDeleted, Deleted.NOT.getCode())
                .list().stream().map(TeachingClass::getTeachingClassId).distinct().collect(Collectors.toList());
        if (CollUtil.isEmpty(teachingClassIds)) {
            return false;
        }
        List<TeachingClassWeek> weekList = teachingClassWeekService.lambdaQuery()
                .in(TeachingClassWeek::getTeachingClassId, teachingClassIds)
                .eq(TeachingClassWeek::getScheduleState, ScheduleState.NORMAL.getCode())
                .list();
        boolean update = teachingClassWeekService.lambdaUpdate()
                .in(TeachingClassWeek::getTeachingClassId, teachingClassIds)
                .eq(TeachingClassWeek::getIsLocked, 2)
                .set(TeachingClassWeek::getIsLocked, 1).update();
        if (update){
            arrangeProcessService.lambdaUpdate().eq(ArrangeProcess::getTaskId,taskId)
                    .set(ArrangeProcess::getIsLocked,1).update();
        }

        //单双拆班问题
        //修改的教学班
        List<Long> tcIds = weekList.stream().map(TeachingClassWeek::getTeachingClassId)
                .distinct().collect(Collectors.toList());
        teachingClassList = teachingClassList.stream()
                .filter(o -> tcIds.contains(o.getTeachingClassId()))
                .collect(Collectors.toList());
        //筛选单双班
        List<TeachingClass> subTeachingClassList = teachingClassList.stream()
                .filter(o -> o.getSubId() != null && o.getSubId() == 0)
                .collect(Collectors.toList());
        if (CollUtil.isNotEmpty(subTeachingClassList)){
            List<String> groups = subTeachingClassList.stream().map(TeachingClass::getUniqueShiftSign)
                    .distinct().collect(Collectors.toList());
            if (CollUtil.isNotEmpty(groups)){
                List<Long> ids = teachingClassService.lambdaQuery()
                        .eq(TeachingClass::getTaskId, taskId)
                        .eq(TeachingClass::getSubId, 0)
                        .in(TeachingClass::getUniqueShiftSign, groups)
                        .eq(TeachingClass::getDeleted, Deleted.NOT.getCode())
                        .list().stream().map(TeachingClass::getTeachingClassId)
                        .distinct().collect(Collectors.toList());

                teachingClassWeekService.lambdaUpdate()
                        .in(TeachingClassWeek::getTeachingClassId,ids)
                        .set(TeachingClassWeek::getIsLocked,1)
                        .update();
            }
        }

        return update;
    }

    @Override
    public Integer isLockedNormal(Integer taskId) {
        ArrangeProcess arrangeProcess = arrangeProcessService.lambdaQuery().eq(ArrangeProcess::getTaskId, taskId).one();
        if(arrangeProcess != null){
            return arrangeProcess.getIsLocked();
        }else {
            return 1;
        }
    }

    @Override
    public String courseToExcel(Integer taskId, Integer state, String gradeId, String gradeName, String majorId, String majorName, String keyword) {
        TaskInfo taskInfo = taskInfoService.getById(taskId);
        String storePath = "/" + taskInfo.getTaskName() + "/课程课表编排-" + LocalDate.now() + ".xlsx";
        String targetPath = GlobalConstant.OUTPUT_EXCEL_PATH + storePath;

        FileUtil.del(targetPath);
        ExcelWriter writer = ExcelUtil.getWriter(targetPath);

        Page<TeachingClassCourseDto> page = new Page<>(1, -1);
        PageInfo<TeachingClassCourseDto> teachingClassPage = this.getTeachingClassCourse(taskId, page, state, gradeId, majorId, keyword);
        List<TeachingClassCourseDto> resultList = teachingClassPage.getList();
        String title = "{}课表编排(课程)  \n  {}";
        writer.merge(10, StrUtil.format(title, taskInfo.getSchoolName(), taskInfo.getTermName()), false);
        writer.setRowHeight(0, 40);
        String filterTem = "年级:{}     排课状态:{}     共:{}个教学班     导出时间:{} ";
        String filter = StrUtil.format(filterTem, StrUtil.isBlank(gradeId) ? "全部年级  " : gradeName,
                ObjUtil.isNull(state) ? "全部" : ScheduleState.getByCode(state).getMsg(),
//                (int) resultList.stream().map(TeachingClassCourseDto::getTeachingClassId).distinct().count(),
                resultList.size(),
                DateUtil.now());
        writer.merge(10, filter, false);
        List<List<String>> rows = new ArrayList<>();
        rows.add(Arrays.asList("班级名称", "课程名称", "授课方式", "任课教师", "上课场地",
                "周次", "场地节次", "排课状态"));
        List<String> row;
        for (TeachingClassCourseDto item : resultList) {
            //任课教师名称
            String teacherName = ExcelFormatUtil.getTeacherName(item.getTeachers());
            //周学时
//            String weekDistribution = ExcelFormatUtil.getWeekHourString(Collections.singletonList(teachingClassWeek));
            //周次
            TeachingClassWeek teachingClassWeek = new TeachingClassWeek().setWeek(item.getWeek())
                    .setHourType(item.getHourType())
                    .setRoomType(item.getRoomType());
            String weeks = ExcelFormatUtil.getWeekString(Collections.singletonList(teachingClassWeek));
            //场地节次
            String siteSection = ExcelFormatUtil.getSiteSection(item.getSchedules());
            row = Arrays.asList(item.getTeachingClassName(), item.getCourseName(),
                    HourType.getByCode(item.getHourType()).getMsg(), teacherName,
                    GlobalConstant.roomTypeMap.get(item.getRoomType()), weeks,
                    siteSection, ScheduleState.getByCode(item.getState()).getMsg());
            rows.add(row);
        }
        writer.write(rows, false);
        ExcelFormatUtil.setFont(writer);
        writer.close();
        return GlobalConstant.ACCESS_PATH + "/static/OutputExcel/" + storePath;
    }

    @Override
    public List<TeachingClassWeekScheduleDto> getTeacherSchedule(Integer taskId, Long teacherId, String schoolId, String term) {
        //获取教师都有哪些教学班
        List<TeachingClassTeacher> teachingClassTeachers = teachingClassMapper.getTeacherTeachingClassByTaskId(Collections.singletonList(taskId), teacherId, Deleted.NOT.getCode());

        Page<TeachingClassWeekScheduleDto> page = new Page<>(1, -1);

        PageInfo<TeachingClassWeekScheduleDto> teachingClassPage = teachingClassService.getTeachingClassAllSchedule(page, taskId, teachingClassTeachers);

        return teachingClassPage.getList();
    }

    private List<TeachingClassWeekScheduleDto> getTeacherTermSchedule(Integer taskId, Long teacherId, String schoolId, String term) {
        //同学期的
        List<Integer> taskIds = taskInfoService.lambdaQuery().eq(TaskInfo::getTerm, term).eq(TaskInfo::getSchoolId, schoolId)
                .list().stream().map(TaskInfo::getTaskId)
                .collect(Collectors.toList());
        List<Long> teachingClassIds = null;
        if (CollUtil.isNotEmpty(taskIds)) {
//            teachingClassIds = teachingClassMapper.getTeacherTeachingClassByTaskId(taskIds, teacherId, Deleted.NOT.getCode());

            //多教师版本
            List<TeachingClassTeacher> teachingClassTeachers = teachingClassMapper.getTeacherTeachingClassByTaskId(taskIds, teacherId, Deleted.NOT.getCode());
            //term教学班
            List<TeachingClassWeekScheduleDto> teachingClassList = teachingClassMapper.getTeachingClassScheduleTeacher(null, teachingClassTeachers);
            if (CollUtil.isNotEmpty(teachingClassList)){
                teachingClassIds = teachingClassList.stream().map(TeachingClassWeekScheduleDto::getTeachingClassId)
                        .distinct().collect(Collectors.toList());
            }
        }

        //获取教师都有哪些教学班
//        List<Long> classIds = teachingClassMapper.getTeacherTeachingClassByTaskId(Collections.singletonList(taskId), teacherId, Deleted.NOT.getCode());

        //多教师版本
        List<Long> classIds = new ArrayList<>();
        List<TeachingClassTeacher> teachingClassTeachers = teachingClassMapper.getTeacherTeachingClassByTaskId(Collections.singletonList(taskId), teacherId, Deleted.NOT.getCode());
        //term教学班
        List<TeachingClassWeekScheduleDto> teachingClassList = teachingClassMapper.getTeachingClassScheduleTeacher(null, teachingClassTeachers);
        if (CollUtil.isNotEmpty(teachingClassList)){
            classIds = teachingClassList.stream().map(TeachingClassWeekScheduleDto::getTeachingClassId)
                    .distinct().collect(Collectors.toList());
        }

        classIds = new ArrayList<>(CollUtil.union(teachingClassIds, classIds));

        Page<TeachingClassWeekScheduleDto> page = new Page<>(1, -1);

        PageInfo<TeachingClassWeekScheduleDto> teachingClassPage = teachingClassService.getTeachingClassAllSchedule(page, null, classIds);

        return teachingClassPage.getList() == null ? new ArrayList<>() : teachingClassPage.getList();
    }

    @Override
    public List<TeachingClassWeekScheduleDto> getClassSchedule(Integer taskId, Long classId) {
        //获取行政班都有哪些教学班
        List<Long> classIds = teachingClassMapper.selectList(new LambdaQueryWrapper<TeachingClass>()
                        .eq(TeachingClass::getTaskId, taskId)
                        .like(TeachingClass::getClassId, classId)
                        .eq(TeachingClass::getDeleted, Deleted.NOT.getCode())
                        .eq(TeachingClass::getTeachingClassType, TeachingClassType.NOSELECT.getCode()))
                .stream().map(TeachingClass::getTeachingClassId).distinct()
                .collect(Collectors.toList());
        Page<TeachingClassWeekScheduleDto> page = new Page<>(1, -1);
        PageInfo<TeachingClassWeekScheduleDto> teachingClassPage = teachingClassService.getTeachingClassAllSchedule(page, taskId, classIds);

        return teachingClassPage.getList() == null ? new ArrayList<>() : teachingClassPage.getList();
    }

    @Override
    public List<TeachingClassWeekScheduleDto> getStudentSchedule(Integer taskId, Long classId) {
        //获取教学班学生所有教学班
        List<Long> classIds = teachingClassStudentMapper.getTeachingClassStudentTcIds(classId);
        Page<TeachingClassWeekScheduleDto> page = new Page<>(1, -1);
        PageInfo<TeachingClassWeekScheduleDto> teachingClassPage = teachingClassService.getTeachingClassAllSchedule(page, taskId, classIds);

        return teachingClassPage.getList() == null ? new ArrayList<>() : teachingClassPage.getList();
    }


    @Override
    public List<TeachingClassWeekScheduleDto> getRoomSchedule(Integer taskId, Long roomId, String schoolId, String term) {
        //获取教学班
//        List<TeachingClass> teachingClasses = teachingClassMapper.selectListByRoomIdHasWeekNum(taskId, roomId);
//        List<Long> ids = teachingClasses
//                .stream().map(TeachingClass::getTeachingClassId).distinct()
//                .collect(Collectors.toList());
        List<Schedule> schedules = scheduleMapper.selectList(new LambdaQueryWrapper<Schedule>()
                .eq(Schedule::getTaskId, taskId)
                .eq(Schedule::getRoomId, roomId));
        List<Long> classIds = schedules.stream().map(Schedule::getTeachingClassId).distinct()
                .collect(Collectors.toList());
//        classIds = new ArrayList<>(CollUtil.union(classIds, ids));
        Page<TeachingClassWeekScheduleDto> page = new Page<>(1, -1);
        PageInfo<TeachingClassWeekScheduleDto> teachingClassPage = teachingClassService.getTeachingClassAllSchedule(page, taskId, classIds);

        List<TeachingClassWeekScheduleDto> list = teachingClassPage.getList();
        if(CollUtil.isNotEmpty(list)){
            List<TeachingClassWeekScheduleDto> res = new ArrayList<>();
            for (TeachingClassWeekScheduleDto item : list) {
//                if (teachingClasses.stream().anyMatch(o ->
//                        Objects.equals(o.getTeachingClassId(), item.getTeachingClassId())
//                                && Objects.equals(o.getHourType(), item.getHourType()))){
//                    res.add(item);
//                    continue;
//                }
                if (schedules.stream().anyMatch(o ->
                        Objects.equals(o.getTeachingClassId(), item.getTeachingClassId())
                                && Objects.equals(o.getHourType(), item.getHourType()))){
                    List<ScheduleDto> roomSchedules= item.getSchedules().stream().filter(o -> Objects.equals(o.getRoomId(), roomId)).collect(Collectors.toList());
                    item.setSchedules(roomSchedules);
                    List<String> timeCodes = roomSchedules.stream().map(ScheduleDto::getTimeCode).collect(Collectors.toList());
                    if (CollUtil.isNotEmpty(item.getConflicts())){
                        List<ScheduleConflictInfo> confilcts = item.getConflicts().stream().filter(o -> timeCodes.contains(o.getTimeCode())).collect(Collectors.toList());
                        item.setConflicts(confilcts);
                    }
                    res.add(item);
                }
            }
            return res;
        }

        return list;
    }

    private List<TeachingClassWeekScheduleDto> getRoomTermSchedule(Integer taskId, Long roomId, String schoolId, String term) {
        //同学期的
        List<Integer> taskIds = taskInfoService.lambdaQuery().eq(TaskInfo::getTerm, term).eq(TaskInfo::getSchoolId, schoolId)
                .list().stream().map(TaskInfo::getTaskId)
                .collect(Collectors.toList());
        List<Long> teachingClassIds = null;
        if (CollUtil.isNotEmpty(taskIds)) {
            teachingClassIds = scheduleMapper.getRoomTeachingClassByTaskId(taskIds, roomId, Deleted.NOT.getCode());
        }

        //获取教学班
        List<Long> classIds = teachingClassMapper.selectListByRoomId(taskId, roomId)
                .stream().map(TeachingClass::getTeachingClassId).distinct()
                .collect(Collectors.toList());
        List<Long> ids = scheduleMapper.selectList(new LambdaQueryWrapper<Schedule>()
                        .eq(Schedule::getTaskId, taskId)
                        .eq(Schedule::getRoomId, roomId)).stream().map(Schedule::getTeachingClassId).distinct()
                .collect(Collectors.toList());
        classIds = new ArrayList<>(CollUtil.union(classIds, ids));
        classIds = new ArrayList<>(CollUtil.union(classIds, teachingClassIds));
        Page<TeachingClassWeekScheduleDto> page = new Page<>(1, -1);
        PageInfo<TeachingClassWeekScheduleDto> teachingClassPage = teachingClassService.getTeachingClassAllSchedule(page, null, classIds);

        return teachingClassPage.getList() == null ? new ArrayList<>() : teachingClassPage.getList();
    }

    /**
     * @param taskId:
     * @param teachingClassId:
     * @Description: 教学班课表
     * @Author: liufeng
     * @Date: 2023/12/21 19:51
     * @return:
     */
    @Override
    public List<TeachingClassWeekScheduleDto> getTeachingClassSchedule(Integer taskId, Long teachingClassId) {
        Page<TeachingClassWeekScheduleDto> page = new Page<>(1, -1);
        PageInfo<TeachingClassWeekScheduleDto> teachingClassPage =
                teachingClassService.getTeachingClassAllSchedule(page, taskId, Collections.singletonList(teachingClassId));

        return teachingClassPage.getList();
    }

    @Override
    public UnionSchedule getUnionSchedule(Integer taskId, Long id, Integer module, String schoolId, String term, String timeCode) {
        UnionSchedule res = new UnionSchedule();
        if (module == 1) {
            Room room = roomMapper.selectById(id);
            res.setScheduleName("关联教室课表：" + room.getBuildingName() + room.getRoomName());
            List<TeachingClassWeekScheduleDto> roomTermSchedule = getRoomTermSchedule(taskId, id, schoolId, term);

            roomTermSchedule = roomTermSchedule.stream()
                    .filter(o -> o.getSchedules().stream()
                            .anyMatch(s -> StrUtil.isNotEmpty(s.getTimeCode())))
                    .peek(o -> o.setSchedules(o.getSchedules().stream()
                            .filter(s -> StrUtil.isNotEmpty(s.getTimeCode())
                            && Objects.equals(s.getRoomId(), id))
                            .collect(Collectors.toList())))
                    .collect(Collectors.toList());

            if (StrUtil.isNotEmpty(timeCode)){
                roomTermSchedule = roomTermSchedule.stream().filter(o ->
                        o.getSchedules().stream().anyMatch(s -> timeCode.contains(s.getTimeCode())))
                        .collect(Collectors.toList());
            }
            res.setSchedules(roomTermSchedule);
        } else if (module == 2){
            Teacher teacher = teacherService.getById(id);
            res.setScheduleName("关联教师课表：" + teacher.getTeacherName() + "-" + teacher.getBaseTeacherId());
            List<TeachingClassWeekScheduleDto> teacherTermSchedule = getTeacherTermSchedule(taskId, id, schoolId, term);

            teacherTermSchedule = teacherTermSchedule.stream()
                    .filter(o -> o.getSchedules().stream()
                            .anyMatch(s -> StrUtil.isNotEmpty(s.getTimeCode())))
                    .peek(o -> o.setSchedules(o.getSchedules().stream()
                            .filter(s -> StrUtil.isNotEmpty(s.getTimeCode()))
                            .collect(Collectors.toList())))
                    .collect(Collectors.toList());

            if (StrUtil.isNotEmpty(timeCode)){
                teacherTermSchedule = teacherTermSchedule.stream().filter(o ->
                                o.getSchedules().stream().anyMatch(s -> timeCode.contains(s.getTimeCode())))
                        .collect(Collectors.toList());
            }
            res.setSchedules(teacherTermSchedule);
        } else if (module == 3) {
            //一个班学生教学计划不一样  所有行政班课表就没用了
//            ClassInfo classInfo = classInfoMapper.selectById(id);
//            res.setScheduleName("关联行政班课表：" + classInfo.getClassName());
//            List<TeachingClassWeekScheduleDto> classSchedule = getClassSchedule(taskId, id);
//            classSchedule = classSchedule.stream()
//                    .filter(o -> o.getSchedules().stream()
//                            .anyMatch(s -> StrUtil.isNotEmpty(s.getTimeCode())))
//                    .peek(o -> o.setSchedules(o.getSchedules().stream()
//                            .filter(s -> StrUtil.isNotEmpty(s.getTimeCode()))
//                            .collect(Collectors.toList())))
//                    .collect(Collectors.toList());
//            if (StrUtil.isNotEmpty(timeCode)){
//                classSchedule = classSchedule.stream().filter(o ->
//                                o.getSchedules().stream().anyMatch(s -> timeCode.contains(s.getTimeCode())))
//                        .collect(Collectors.toList());
//            }
//            res.setSchedules(classSchedule);
            res.setSchedules(new ArrayList<>());
        }else if (module == 4) {
            res.setScheduleName("关联学生课表：");
            List<TeachingClassWeekScheduleDto> studentSchedule = getStudentSchedule(taskId, id);
            studentSchedule = studentSchedule.stream()
                    .filter(o -> o.getSchedules().stream()
                            .anyMatch(s -> StrUtil.isNotEmpty(s.getTimeCode())))
                    .peek(o -> o.setSchedules(o.getSchedules().stream()
                            .filter(s -> StrUtil.isNotEmpty(s.getTimeCode()))
                            .collect(Collectors.toList())))
                    .collect(Collectors.toList());
            if (StrUtil.isNotEmpty(timeCode)){
                studentSchedule = studentSchedule.stream().filter(o ->
                                o.getSchedules().stream().anyMatch(s -> timeCode.contains(s.getTimeCode())))
                        .collect(Collectors.toList());
            }
            res.setSchedules(studentSchedule);
        }
        return res;
    }

    /**
     * @param taskId:
     * @param generateTeachingClassUnits:
     * @Description: 生成教学班课表初始数据
     * @Author: liufeng
     * @Date: 2023/12/21 9:47
     * @return:
     */
    @Override
    public List<Schedule> generateTeachingClassUnit(Integer taskId, List<GenerateTeachingClassUnitInput> generateTeachingClassUnits) {
        //待生成初始化课表
        List<Schedule> scheduleList = new ArrayList<>();
        GenerateSchedulingData generateSchedulingData = new GenerateSchedulingData();
        List<ArrangeTeachingClassDto> teachingClassList = BeanUtil.copyToList(generateTeachingClassUnits, ArrangeTeachingClassDto.class);
        LinkedList<TeachingClassUnit> teachingClassUnits = generateSchedulingData.convertToTeachingClassUnit(taskId, teachingClassList, 0,new ArrayList<>());
        teachingClassUnits.forEach(a -> {
            String uuid = UUID.randomUUID().toString();
            for (int i = 0; i < a.getConnectSection(); i++) {
                scheduleList.add(new Schedule().setTaskId(taskId)
                        .setTeachingClassId(a.getTeachingClassId())
                        .setTeachingClassName(a.getTeachingClassName())
                        .setCourseId(a.getCourseId())
                        .setCourseName(a.getCourseName())
                        .setHourType(a.getTeachingType())
                        .setWeek(a.getClassWeeks())
                        .setRoomId(StrUtil.isEmpty(a.getRoomId()) ? null : Long.valueOf(a.getRoomId()))
                        .setRoomType(a.getRoomType())
                        .setConnectSection(a.getConnectSection())
                        .setTimeGroup(uuid));
            }
        });
        if (scheduleList.size() > 0) {
            //批量插入课表，大数据批量插入
            Consumer<List<Schedule>> scheduleConsumer = o -> scheduleMapper.addBatch(o);
            BatchInsert.batchSplitInsert(scheduleList, scheduleConsumer);
//            this.saveBatch(scheduleList);
        }
        return scheduleList;
    }

    /**
     * @param taskId:
     * @Description: 未排课状态教学班生成教学班课表初始数据
     * @Author: liufeng
     * @Date: 2023/12/21 9:47
     * @return:
     */
    @Override
    public Boolean allToTeachingClassUnit(Integer taskId) {
        Integer count = baseMapper.getCount(taskId);
        if (count == 0) {
            return false;
        }
        //所有排课状态 未排  但需要的教学班
        List<GenerateTeachingClassUnitInput> unArranges =
                teachingClassMapper.getAllUnArrangeTeachingClass(taskId, ScheduleState.UNARRANGE.getCode());
        unArranges = unArranges.stream().filter(o -> StrUtil.isNotEmpty(o.getWeek())
                && (o.getWeekNum() != null && o.getWeekNum() != 0)
                && o.getConnectSection() != null).collect(Collectors.toList());
        if (CollUtil.isEmpty(unArranges)) {
            return true;
        }
        List<Long> tcIds = unArranges.stream().map(GenerateTeachingClassUnitInput::getTeachingClassId).distinct().collect(Collectors.toList());
        List<ScheduleDto> arranged = baseMapper.getAllScheduleByTeachingClassIds(taskId, tcIds);
        //为空说明没有排 直接生成原始数据
        if (CollUtil.isEmpty(arranged)) {
            generateTeachingClassUnit(taskId, unArranges);
        } else {
            //排除  排了一半  但是状态也是 未排的教学班
            List<GenerateTeachingClassUnitInput> add = new ArrayList<>();

            Map<Long, List<ScheduleDto>> scheduleMap = arranged.stream()
                    .collect(Collectors.groupingBy(ScheduleDto::getTeachingClassId));
            for (GenerateTeachingClassUnitInput unArrange : unArranges) {
                List<ScheduleDto> schedules = scheduleMap.get(unArrange.getTeachingClassId());
                if (CollUtil.isEmpty(schedules)) {
                    //没有课表 直接生成
                    add.add(unArrange);
                    continue;
                }
                //不存在课表  生成
                if (!schedules.stream().map(ScheduleDto::getHourType)
                        .collect(Collectors.toList())
                        .contains(unArrange.getHourType())) {
                    add.add(unArrange);
                }
            }

            if (CollUtil.isNotEmpty(add)) {
                generateTeachingClassUnit(taskId, add);
            }
        }
        return true;

    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeSchedule(Integer taskId, List<Schedule> scheduleList) {
        if (CollUtil.isEmpty(scheduleList)) {
            throw new BizException("删除课表为空");
        }
        //删除课表timeCode和教室id
        TeachingClassWeek teachingClassWeek = teachingClassWeekService.lambdaQuery()
                .eq(TeachingClassWeek::getTeachingClassId, scheduleList.get(0).getTeachingClassId())
                .eq(TeachingClassWeek::getHourType, scheduleList.get(0).getHourType())
                .eq(TeachingClassWeek::getDeleted, Deleted.NOT.getCode()).one();
        Long roomId = teachingClassWeek.getRoomId();
        scheduleList.forEach(o -> {
            o.setTimeCode(null);
            o.setRoomId(roomId);
        });
        baseMapper.removeSchedule(roomId, scheduleList);
    }

    /**
     * @Description: 拆分连上课表
     * @Author: liufeng
     * @Date: 2024/3/26 14:19
     * @param taskId:
     * @param subScheduleDto:
     * @return:
     */
    @Override
    public void subSchedule(Integer taskId, SubScheduleDto subScheduleDto){
        if(CollUtil.isEmpty(subScheduleDto.getScheduleIds())){
            return;
        }
        List<Schedule> updateList = scheduleMapper.selectList(
                new LambdaQueryWrapper<Schedule>()
                        .eq(Schedule::getTaskId,taskId)
                        .in(Schedule::getId,subScheduleDto.getScheduleIds()));
        if (subScheduleDto.getIsSub()){
            updateList.forEach(o -> {
                o.setConnectSection(1);
                String timeGroup = o.getTimeGroup();
                o.setReserve(timeGroup);
                o.setTimeGroup(UUID.randomUUID().toString());
            });
        }
        if (CollUtil.isNotEmpty(updateList)){
            scheduleMapper.subSchedule(updateList);
        }
    }


    /**
     * @param schoolId :
     * @param term     :
     * @param gradeId
     * @param classId
     * @param keyword
     * @Description: 行政班总表
     * @Author: liufeng
     * @Date: 2023/12/27 9:59
     * @return:
     */
    @Override
    public PageInfo<ClassInfo> getAllClassSchedule(Integer taskId, String schoolId, String term, String gradeId, Long classId, String keyword, Integer currentPage, Integer pageSize) {
        List<ClassInfo> res = new ArrayList<>();
        List<ViewSchedule> viewScheduleList = getAllSchedule(taskId, schoolId, term);
        if (CollUtil.isNotEmpty(viewScheduleList)) {
            //同学期
//            List<Integer> taskIds = taskInfoService.lambdaQuery()
//                    .eq(TaskInfo::getSchoolId, schoolId)
//                    .eq(TaskInfo::getTerm, term)
//                    .eq(TaskInfo::getDeleted, Deleted.NOT.getCode()).list()
//                    .stream().map(TaskInfo::getTaskId).distinct()
//                    .collect(Collectors.toList());

            List<Integer> taskIds = Collections.singletonList(taskId);
            Map<Long, ClassInfo> classMap = classInfoMapper.getClassNameTerm(taskIds)
                    .stream().collect(Collectors.toMap(ClassInfo::getId, Function.identity()));

            Map<String, List<ViewSchedule>> stringListMap = viewScheduleList.stream()
                    .collect(Collectors.groupingBy(ViewSchedule::getToClass));

            for (Map.Entry<String, List<ViewSchedule>> entry : stringListMap.entrySet()) {
                if (StrUtil.isNotEmpty(entry.getKey())) {
                    for (String id : entry.getKey().split(",")) {
                        List<ViewSchedule> schedules = classMap.get(Long.parseLong(id)).getSchedules();
                        if (schedules == null) {
                            schedules = new ArrayList<>(entry.getValue());
                        } else {
                            schedules.addAll(entry.getValue());
                        }
                        classMap.get(Long.parseLong(id)).setSchedules(schedules);
                    }
                }
            }
            res = new ArrayList<>(classMap.values()).stream().sorted(Comparator.comparing(ClassInfo::getClassName)).collect(Collectors.toList());
        }

        //筛选
        if (res != null && !res.isEmpty()) {
            //筛选对应的周次以及课时编码的数据
            res = res.stream()
                    .filter(classInfo -> StrUtil.isEmpty(gradeId) || classInfo.getGradeId().equals(gradeId))
                    .filter(classInfo -> classId == null || Objects.equals(classInfo.getId(), classId))
                    .filter(classInfo -> StrUtil.isEmpty(keyword) || classInfo.getClassName().contains(keyword))
                    .collect(Collectors.toList());
        }

        return PagingUtil.getPages(currentPage, pageSize, res);
    }

    /**
     * @param schoolId :
     * @param term     :
     * @param keyword  :
     * @Description: 全校教师课表
     * @Author: liufeng
     * @Date: 2023/12/26 20:44
     * @return:
     */
    @Override
    public PageInfo<AllScheduleVo> getAllTeacherSchedule(Integer taskId, String schoolId, String keyword, String term, Integer currentPage, Integer pageSize) {
        List<AllScheduleVo> res = new ArrayList<>();
        List<ViewSchedule> viewScheduleList = getAllSchedule(taskId, schoolId, term);

        viewScheduleList = viewScheduleList.stream().filter(o -> StrUtil.isNotEmpty(o.getTeacherIds())).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(viewScheduleList)) {
            Map<String, List<ViewSchedule>> teacherSchedulesMap = new HashMap<>();
            Map<String, List<ViewSchedule>> map = viewScheduleList.stream()
                    .collect(Collectors.groupingBy(ViewSchedule::getTeacherName));
            for (Map.Entry<String, List<ViewSchedule>> entry : map.entrySet()) {
                String teacherKey = entry.getKey();
                if (StrUtil.isNotEmpty(teacherKey)) {
                    for (String teacher : teacherKey.split(",")) {
                        teacherSchedulesMap.computeIfAbsent(teacher,k -> new ArrayList<ViewSchedule>())
                                        .addAll(entry.getValue());
                    }
                }
            }
            for (Map.Entry<String, List<ViewSchedule>> entry : teacherSchedulesMap.entrySet()) {
                res.add(new AllScheduleVo().setName(entry.getKey())
                        .setSchedules(entry.getValue()));
            }

        }

        //没课的教师
        List<AllScheduleVo> teachers = teacherMapper.getTeacherNameForSchedule(schoolId, term, Deleted.NOT.getCode());
        if (CollUtil.isNotEmpty(viewScheduleList)){
            HashSet<Long> remove = new HashSet<>();
            //多教师版本
            for (ViewSchedule viewSchedule : viewScheduleList) {
                String teacherIds = viewSchedule.getTeacherIds();
                if (StrUtil.isNotEmpty(teacherIds)){
                    for (String teacherId : teacherIds.split(",")) {
                        remove.add(Long.valueOf(teacherId));
                    }
                }
            }
            teachers = teachers.stream().filter(o -> !remove.contains(o.getId())).collect(Collectors.toList());
        }
        res.addAll(teachers);

        //筛选项
        if (CollUtil.isNotEmpty(res) && StrUtil.isNotEmpty(keyword)){
            res = res.stream().filter(o -> o.getName().contains(keyword))
                    .collect(Collectors.toList());
        }
        return PagingUtil.getPages(currentPage, pageSize, res);
    }

    /**
     * @param schoolId   :
     * @param term       :
     * @param campusId
     * @param buildingId
     * @param keyword
     * @Description: 全校教室课表
     * @Author: liufeng
     * @Date: 2023/12/26 20:22
     * @return:
     */
    @Override
    public PageInfo<AllScheduleVo> getAllRoomSchedule(Integer taskId, String schoolId, String term, String campusId, Integer buildingId, String keyword, Integer currentPage, Integer pageSize) {
        List<AllScheduleVo> res = new ArrayList<>();
        List<ViewSchedule> viewScheduleList = getAllSchedule(taskId, schoolId, term);
        if (CollUtil.isNotEmpty(viewScheduleList)) {
            Map<Long, List<ViewSchedule>> map = viewScheduleList.stream()
                    .collect(Collectors.groupingBy(ViewSchedule::getRoomId));
            for (Map.Entry<Long, List<ViewSchedule>> entry : map.entrySet()) {
                ViewSchedule viewSchedule = entry.getValue().get(0);
                res.add(new AllScheduleVo()
                        .setName(viewSchedule.getRoomName())
                        .setCampusId(viewSchedule.getCampusId())
                        .setBuildingId(viewSchedule.getBuildingId())
                        .setSchedules(entry.getValue()));
            }
            res = res.stream().sorted(Comparator.comparing(AllScheduleVo::getName)).collect(Collectors.toList());
        }

        //没课的
        List<AllScheduleVo> rooms = roomMapper.getRoomNameForSchedule(schoolId, term, Deleted.NOT.getCode());
        if (CollUtil.isNotEmpty(viewScheduleList)){
            HashSet<Long> remove = viewScheduleList.stream().map(ViewSchedule::getRoomId).distinct().collect(Collectors.toCollection(HashSet::new));
            rooms = rooms.stream().filter(o -> !remove.contains(o.getId())).collect(Collectors.toList());
        }
        rooms = rooms.stream().sorted(Comparator.comparing(AllScheduleVo::getName)).collect(Collectors.toList());
        res.addAll(rooms);

        //筛选
        if (CollUtil.isNotEmpty(res)) {
            //筛选对应的周次以及课时编码的数据
            res = res.stream()
                    .filter(o -> StrUtil.isEmpty(campusId) || o.getCampusId().equals(campusId))
                    .filter(o -> buildingId == null || Objects.equals(o.getBuildingId(), buildingId))
                    .filter(o -> StrUtil.isEmpty(keyword) || o.getName().contains(keyword))
                    .collect(Collectors.toList());
        }
        return PagingUtil.getPages(currentPage, pageSize, res);
    }

    /**
     * @param schoolId :
     * @param term     :
     * @param courseId
     * @param keyword
     * @Description: 全校教学班课表
     * @Author: liufeng
     * @Date: 2023/12/26 20:22
     * @return:
     */
    @Override
    public PageInfo<AllScheduleVo> getAllTeachingClassSchedule(Integer taskId, String schoolId, String term, Long courseId, String keyword, Integer currentPage, Integer pageSize) {
        List<AllScheduleVo> res = new ArrayList<>();
        List<ViewSchedule> viewScheduleList = getAllSchedule(taskId, schoolId, term);
        if (CollUtil.isNotEmpty(viewScheduleList)) {
            Map<Long, List<ViewSchedule>> map = viewScheduleList.stream()
                    .collect(Collectors.groupingBy(ViewSchedule::getTeachingClassId));
            for (Map.Entry<Long, List<ViewSchedule>> entry : map.entrySet()) {
                ViewSchedule viewSchedule = entry.getValue().get(0);
                res.add(new AllScheduleVo()
                        .setName(viewSchedule.getTeachingClassName())
                        .setCourseId(viewSchedule.getCourseId())
                        .setSchedules(entry.getValue()));
            }
            res = res.stream().sorted(Comparator.comparing(AllScheduleVo::getName)).collect(Collectors.toList());
        }
//        res = res.stream().sorted(Comparator.comparing(AllScheduleVo::getName)).collect(Collectors.toList());

        //没课的
        List<AllScheduleVo> teachingClass = teachingClassMapper.getTeachingClassNameForSchedule(taskId, Deleted.NOT.getCode());
        if (CollUtil.isNotEmpty(viewScheduleList)){
            HashSet<Long> remove = viewScheduleList.stream().map(ViewSchedule::getTeachingClassId).distinct().collect(Collectors.toCollection(HashSet::new));
            teachingClass = teachingClass.stream().filter(o -> !remove.contains(o.getId())).collect(Collectors.toList());
        }
        teachingClass = teachingClass.stream().sorted(Comparator.comparing(AllScheduleVo::getName)).collect(Collectors.toList());
        res.addAll(teachingClass);

        //筛选
        if (CollUtil.isNotEmpty(res)) {
            //筛选对应的周次以及课时编码的数据
            res = res.stream()
                    .filter(o -> courseId == null || Objects.equals(o.getCourseId(), courseId))
                    .filter(o -> StrUtil.isEmpty(keyword) || o.getName().contains(keyword))
                    .collect(Collectors.toList());
        }

        return PagingUtil.getPages(currentPage, pageSize, res);
    }

    private List<ViewSchedule> getAllSchedule(Integer taskId, String schoolId, String term) {
//        List<Integer> taskIds = taskInfoService.lambdaQuery()
//                .eq(TaskInfo::getSchoolId, schoolId)
//                .eq(TaskInfo::getTerm, term)
//                .eq(TaskInfo::getDeleted, Deleted.NOT.getCode()).list()
//                .stream().map(TaskInfo::getTaskId).distinct()
//                .collect(Collectors.toList());
        List<Integer> taskIds = Collections.singletonList(taskId);
        if (CollUtil.isEmpty(taskIds)) {
            return null;
        }
        List<ViewSchedule> viewScheduleList = scheduleMapper.getAllSchedule(taskIds);
        if (CollUtil.isNotEmpty(viewScheduleList)) {
            //填充教师
            Map<Long, List<Teacher>> teacherMap = teacherService.lambdaQuery()
                    .eq(Teacher::getSchoolId, schoolId)
                    .eq(Teacher::getTerm, term)
                    .eq(Teacher::getDeleted, Deleted.NOT.getCode()).list()
                    .stream().collect(Collectors.groupingBy(Teacher::getTeacherId));
            for (ViewSchedule viewSchedule : viewScheduleList) {
                if (StrUtil.isEmpty(viewSchedule.getTeacherIds())) {
                    continue;
                }
                //多教师版本
                String teacherIds = viewSchedule.getTeacherIds();
                for (String teacherId : teacherIds.split(",")) {
                    List<Teacher> teachers = teacherMap.get(Long.valueOf(teacherId));
                    if (CollUtil.isNotEmpty(teachers)){
                        String name = StrUtil.isEmpty(viewSchedule.getTeacherName()) ?
                                teachers.get(0).getTeacherName()
                                : viewSchedule.getTeacherName() + "," + teachers.get(0).getTeacherName();
                        viewSchedule.setTeacherName(name);
                    }
                }
            }
        }
        return viewScheduleList;
    }


    @Override
    public String classScheduleToExcel(Integer taskId, Long classId) {

        TaskInfo taskInfo = taskInfoService.getById(taskId);
        String storePath = "/" + taskInfo.getTaskName() + "/行政班课表-" + LocalDate.now() + ".xlsx";
        String targetPath = GlobalConstant.OUTPUT_EXCEL_PATH + storePath;

        FileUtil.del(targetPath);
        ExcelWriter writer = ExcelUtil.getWriter(targetPath);

        ClassInfo classInfo = classInfoMapper.selectOne(new LambdaQueryWrapper<ClassInfo>()
                .eq(ClassInfo::getTaskId, taskId)
                .eq(ClassInfo::getId, classId));
        List<Long> classIds = teachingClassMapper.selectList(new LambdaQueryWrapper<TeachingClass>()
                        .eq(TeachingClass::getTaskId, taskId)
                        .like(TeachingClass::getClassId, String.valueOf(classId))
                        .eq(TeachingClass::getDeleted, Deleted.NOT.getCode())
                        .eq(TeachingClass::getTeachingClassType, TeachingClassType.NOSELECT.getCode()))
                .stream().map(TeachingClass::getTeachingClassId).distinct()
                .collect(Collectors.toList());
        Page<TeachingClassWeekScheduleDto> page = new Page<>(1, -1);
        PageInfo<TeachingClassWeekScheduleDto> teachingClassPage = teachingClassService.getTeachingClassSchedule(page, taskId, classIds, null);
        List<TeachingClassWeekScheduleDto> resultList = teachingClassPage.getList();
        //根据最大周次生成课表模板
        int periods = basicRuleService.getMaxPeriodScheme(taskId, taskInfo.getSchoolId(), taskInfo.getTerm()).getPeriodSchemes().size();
        String title = "{} 行政班课表  \n  {}";
        writer.merge(7, StrUtil.format(title, classInfo.getClassName(), taskInfo.getTermName()), false);
        writer.setRowHeight(0, 40);
        long courseNum = resultList.stream().filter(o -> CollUtil.isNotEmpty(o.getSchedules())).map(TeachingClassWeekScheduleDto::getCourseId).distinct().count();
        long sectionNum = resultList.stream()
                .flatMap(studentTeachingClass -> studentTeachingClass.getSchedules().stream())
                .filter(schedule -> ObjUtil.isNotNull(schedule.getTimeCode())).count();
        String filterTem = "共: {}门课程，{}节课   导出时间:{} ";
        String filter = StrUtil.format(filterTem, courseNum, sectionNum, DateUtil.now());
        writer.merge(7, filter, false);
        List<List<String>> rows = ExcelFormatUtil.getScheduleFormat(periods, 7);
        for (TeachingClassWeekScheduleDto item : resultList) {
            //以及排好的课节
            List<ScheduleDto> arrangeSchedule = item.getSchedules().stream().filter(scheduleDto -> StrUtil.isNotBlank(scheduleDto.getTimeCode())).collect(Collectors.toList());
            //根据授课类型分组 使用TreeMap来排序
            TreeMap<Integer, List<ScheduleDto>> mapByHourType = arrangeSchedule.stream()
                    .collect(Collectors.groupingBy(ScheduleDto::getHourType, TreeMap::new, Collectors.toList()));
            mapByHourType.forEach((hourType, byHourTypeList) -> {
                //根据timeCode分组
                byHourTypeList.stream().collect(Collectors.groupingBy(ScheduleDto::getTimeCode)).forEach((timeCode, byTimeCodeList) -> {
                    //根据week分组
                    byTimeCodeList.stream().collect(Collectors.groupingBy(ScheduleDto::getWeek)).forEach((week, byWeekList) -> {
                        //单个教学班 单个讲授类型 单个周次  单个节次 对应字符串
//                            String scheduleHour = "{courseName}({hourType}) \n{teachingClassName}\n{buildingName}{roomName}\n{week}"
                        String scheduleHour = "{}({}) \n{}\n{}\n{}{}\n{}";
                        //key 0101  节次
                        int index = Integer.parseInt(timeCode.substring(2, 4));
                        String buildingName = byWeekList.get(0).getBuildingName();
                        String roomName = byWeekList.get(0).getRoomName();
                        String weekString = StrUtil.format("[{}]周", WeekUtil.binaryToString(week));
                        String teacherNames = ExcelFormatUtil.getTeacherName(item.getTeachers());

                        String format = StrUtil.format(scheduleHour, item.getCourseName(), GlobalConstant.hourTypeMap.get(hourType)
                                , item.getTeachingClassName(), teacherNames,buildingName, roomName, weekString);
                        String s = rows.get(index).get(GlobalConstant.dayCode.indexOf(timeCode.substring(0, 2)) + 1);
                        if ("--".equals(s)) {
                            s = "";
                        } else {
                            s += "\n";
                        }
                        rows.get(index).set(GlobalConstant.dayCode.indexOf(timeCode.substring(0, 2)) + 1, s + format);
                    });
                });
            });
        }
        writer.write(rows, false);
        setExcelForm(writer, rows, 2);
        writer.close();
        return GlobalConstant.ACCESS_PATH + "/static/OutputExcel" + storePath;
    }

    //填充课表 上课数据
    public void fillSchedule(List<List<String>> rows, List<ScheduleDto> schedule, Map<Long, List<Teacher>> teachingClassToTeacher) {
        Map<String, List<ScheduleDto>> byTimeCode = schedule.stream().collect(Collectors.groupingBy(ScheduleDto::getTimeCode));
        byTimeCode.forEach((timeCode, byTimeCodeList) -> {
            //key 0101  节次
            int index = Integer.parseInt(timeCode.substring(2, 4));
            //单节课数据
            StringJoiner singleSchedule = new StringJoiner("\n");
            for (ScheduleDto allScheduleDto : byTimeCodeList) {
                //单个教学班数据 {courseName}{单双}\n{teachName}\n{buildingName}{roomName}
                String singleScheduleTemplate = "{} \n {} \n {}{}";
                String courseName = allScheduleDto.getCourseName();
                String teachName = teachingClassToTeacher.getOrDefault(allScheduleDto.getTeachingClassId(), new ArrayList<>()).stream().map(Teacher::getTeacherName).collect(Collectors.joining(","));
                singleSchedule.add(StrUtil.format(singleScheduleTemplate,
                        courseName, teachName, allScheduleDto.getBuildingName(), allScheduleDto.getRoomName()));
            }
            rows.get(index).set(GlobalConstant.dayCode.indexOf(timeCode.substring(0, 2)) + 1, singleSchedule.toString());
        });
    }

    /**
     * @param taskId:
     * @param teacherId:
     * @Description: 导出教师课表
     * @Author: liufeng
     * @Date: 2023/12/28 16:14
     * @return:
     */
    @Override
    public String teacherScheduleToExcel(Integer taskId, Long teacherId) {
        TaskInfo taskInfo = taskInfoService.getById(taskId);
        String storePath = "/" + taskInfo.getTaskName() + "/教师课表-" + LocalDate.now() + ".xlsx";
        String targetPath = GlobalConstant.OUTPUT_EXCEL_PATH + storePath;

        FileUtil.del(targetPath);
        ExcelWriter writer = ExcelUtil.getWriter(targetPath);

        Teacher teacher = teacherService.getById(teacherId);
        //获取教师都有哪些教学班
        //多教师版本
        //获取教师都有哪些教学班
        List<TeachingClassTeacher> teachingClassTeachers = teachingClassMapper.getTeacherTeachingClassByTaskId(Collections.singletonList(taskId), teacherId, Deleted.NOT.getCode());
        Page<TeachingClassWeekScheduleDto> page = new Page<>(1, -1);
        PageInfo<TeachingClassWeekScheduleDto> teachingClassPage = teachingClassService.getTeachingClassAllSchedule(page, taskId, teachingClassTeachers);

//        List<Long> classIds = teachingClassTeacherMapper.selectList(new LambdaQueryWrapper<TeachingClassTeacher>().eq(TeachingClassTeacher::getTeacherId, teacherId))
//                .stream().map(TeachingClassTeacher::getTeachingClassId).distinct().collect(Collectors.toList());
//        Page<TeachingClassWeekScheduleDto> page = new Page<>(1, -1);
//        PageInfo<TeachingClassWeekScheduleDto> teachingClassPage = teachingClassService.getTeachingClassSchedule(page, taskId, classIds, null);

        List<TeachingClassWeekScheduleDto> resultList = teachingClassPage.getList();

        //根据最大周次生成课表模板
        int periods = basicRuleService.getMaxPeriodScheme(taskId, taskInfo.getSchoolId(), taskInfo.getTerm()).getPeriodSchemes().size();
        String title = "{} 教师课表  \n  {}";
        writer.merge(7, StrUtil.format(title, teacher.getTeacherName(), taskInfo.getTermName()), false);
        writer.setRowHeight(0, 40);
        long courseNum = resultList.stream().filter(o -> CollUtil.isNotEmpty(o.getSchedules())).map(TeachingClassWeekScheduleDto::getCourseId).distinct().count();
        long sectionNum = resultList.stream()
                .flatMap(studentTeachingClass -> studentTeachingClass.getSchedules().stream())
                .filter(schedule -> ObjUtil.isNotNull(schedule.getTimeCode())).count();
        String filterTem = "共: {}门课程，{}节课   导出时间:{} ";
        String filter = StrUtil.format(filterTem, courseNum, sectionNum, DateUtil.now());
        writer.merge(7, filter, false);
        List<List<String>> rows = ExcelFormatUtil.getScheduleFormat(periods, 7);
        for (TeachingClassWeekScheduleDto item : resultList) {
            //以及排好的课节
            List<ScheduleDto> arrangeSchedule = item.getSchedules().stream().filter(scheduleDto -> StrUtil.isNotBlank(scheduleDto.getTimeCode())).collect(Collectors.toList());
            //根据授课类型分组 使用TreeMap来排序
            TreeMap<Integer, List<ScheduleDto>> mapByHourType = arrangeSchedule.stream()
                    .collect(Collectors.groupingBy(ScheduleDto::getHourType, TreeMap::new, Collectors.toList()));
            mapByHourType.forEach((hourType, byHourTypeList) -> {
                //根据timeCode分组
                byHourTypeList.stream().collect(Collectors.groupingBy(ScheduleDto::getTimeCode)).forEach((timeCode, byTimeCodeList) -> {
                    //根据week分组
                    byTimeCodeList.stream().collect(Collectors.groupingBy(ScheduleDto::getWeek)).forEach((week, byWeekList) -> {
                        //单个教学班 单个讲授类型 单个周次  单个节次 对应字符串
//                            String scheduleHour = "{courseName}({hourType}) \n{teachingClassName}\n{buildingName}{roomName}\n{week}"
                        String scheduleHour = "{}({}) \n{}\n{}{}\n{}";
                        //key 0101  节次
                        int index = Integer.parseInt(timeCode.substring(2, 4));
                        String buildingName = byWeekList.get(0).getBuildingName();
                        String roomName = byWeekList.get(0).getRoomName();
                        String weekString = StrUtil.format("[{}]周", WeekUtil.binaryToString(week));
                        String format = StrUtil.format(scheduleHour, item.getCourseName(), GlobalConstant.hourTypeMap.get(hourType)
                                , item.getTeachingClassName(), buildingName, roomName, weekString);
                        rows.get(index).set(GlobalConstant.dayCode.indexOf(timeCode.substring(0, 2)) + 1, format);
                    });
                });
            });
        }
        writer.write(rows, false);
        setExcelForm(writer, rows, 2);
        writer.close();
        return GlobalConstant.ACCESS_PATH + "/static/OutputExcel" + storePath;
    }

    /**
     * @param taskId:
     * @param roomId:
     * @Description: 导出教室课表
     * @Author: liufeng
     * @Date: 2023/12/28 16:14
     * @return:
     */
    @Override
    public String roomScheduleToExcel(Integer taskId, Long roomId) {
        TaskInfo taskInfo = taskInfoService.getById(taskId);
        String storePath = "/" + taskInfo.getTaskName() + "/教室课表-" + LocalDate.now() + ".xlsx";
        String targetPath = GlobalConstant.OUTPUT_EXCEL_PATH + storePath;

        FileUtil.del(targetPath);
        ExcelWriter writer = ExcelUtil.getWriter(targetPath);

        Room room = roomMapper.selectById(roomId);
        List<Schedule> scheduleByRoom = scheduleMapper.selectList(
                new LambdaQueryWrapper<Schedule>()
                        .eq(Schedule::getRoomId, roomId)
                        .eq(Schedule::getDeleted, Deleted.NOT.getCode()));

        //获取教室都有哪些教学班
        Page<TeachingClassWeekScheduleDto> page = new Page<>(1, -1);
        List<Long> classIds = scheduleByRoom.stream().map(Schedule::getTeachingClassId).collect(Collectors.toList());
        PageInfo<TeachingClassWeekScheduleDto> teachingClassPage = teachingClassService.getTeachingClassSchedule(page, taskId, classIds, roomId);
        List<TeachingClassWeekScheduleDto> resultList = teachingClassPage.getList();

        //根据最大周次生成课表模板
        int periods = basicRuleService.getMaxPeriodScheme(taskId, taskInfo.getSchoolId(), taskInfo.getTerm()).getPeriodSchemes().size();
        String title = "{} 教室课表  \n  {}";
        writer.merge(7, StrUtil.format(title, room.getRoomName(), taskInfo.getTermName()), false);
        writer.setRowHeight(0, 40);
        long courseNum = resultList.stream().filter(o -> CollUtil.isNotEmpty(o.getSchedules())).map(TeachingClassWeekScheduleDto::getCourseId).distinct().count();
        long sectionNum = resultList.stream()
                .flatMap(studentTeachingClass -> studentTeachingClass.getSchedules().stream())
                .filter(schedule -> ObjUtil.isNotNull(schedule.getTimeCode())).count();
        String filterTem = "共: {}门课程，{}节课   导出时间:{} ";
        String filter = StrUtil.format(filterTem, courseNum, sectionNum, DateUtil.now());
        writer.merge(7, filter, false);
        List<List<String>> rows = ExcelFormatUtil.getScheduleFormat(periods, 7);
        for (TeachingClassWeekScheduleDto item : resultList) {
            //以及排好的课节
            List<ScheduleDto> arrangeSchedule = item.getSchedules().stream().filter(scheduleDto -> StrUtil.isNotBlank(scheduleDto.getTimeCode())).collect(Collectors.toList());
            //根据授课类型分组 使用TreeMap来排序
            TreeMap<Integer, List<ScheduleDto>> mapByHourType = arrangeSchedule.stream()
                    .collect(Collectors.groupingBy(ScheduleDto::getHourType, TreeMap::new, Collectors.toList()));
            mapByHourType.forEach((hourType, byHourTypeList) -> {
                //根据timeCode分组
                byHourTypeList.stream().collect(Collectors.groupingBy(ScheduleDto::getTimeCode)).forEach((timeCode, byTimeCodeList) -> {
                    //根据week分组
                    byTimeCodeList.stream().collect(Collectors.groupingBy(ScheduleDto::getWeek)).forEach((week, byWeekList) -> {
                        //单个教学班 单个讲授类型 单个周次  单个节次 对应字符串
//                            String scheduleHour = "{courseName}({hourType}) \n{teachingClassName}\n{buildingName}{roomName}\n{week}"
                        String scheduleHour = "{}({}) \n{}\n{}\n{}{}\n{}";
                        //key 0101  节次
                        int index = Integer.parseInt(timeCode.substring(2, 4));
                        String buildingName = byWeekList.get(0).getBuildingName();
                        String roomName = byWeekList.get(0).getRoomName();
                        String weekString = StrUtil.format("[{}]周", WeekUtil.binaryToString(week));
                        String teacherNames = ExcelFormatUtil.getTeacherName(item.getTeachers());

                        String format = StrUtil.format(scheduleHour, item.getCourseName(), Objects.requireNonNull(HourType.getByCode(hourType)).getMsg(),
                                item.getTeachingClassName(), teacherNames, buildingName, roomName, weekString);
                        rows.get(index).set(GlobalConstant.dayCode.indexOf(timeCode.substring(0, 2)) + 1, format);
                    });
                });
            });
        }
        writer.write(rows, false);
        setExcelForm(writer, rows, 2);
        writer.close();
        return GlobalConstant.ACCESS_PATH + "/static/OutputExcel" + storePath;
    }


    @Override
    public String teachingClassScheduleToExcel(Integer taskId, Long teachingClassId) {
        TaskInfo taskInfo = taskInfoService.getById(taskId);
        TeachingClass teachingClass = teachingClassService.lambdaQuery()
                .eq(TeachingClass::getDeleted, Deleted.NOT.getCode())
                .eq(TeachingClass::getTeachingClassId, teachingClassId)
                .one();
        String storePath = "/" + taskInfo.getTaskName() + "/教学班课表-" + LocalDate.now() + ".xlsx";
        String targetPath = GlobalConstant.OUTPUT_EXCEL_PATH + storePath;

        FileUtil.del(targetPath);
        ExcelWriter writer = ExcelUtil.getWriter(targetPath);


        //获取教学班
        Page<TeachingClassWeekScheduleDto> page = new Page<>(1, -1);
        List<Long> classIds = Collections.singletonList(teachingClassId);
        PageInfo<TeachingClassWeekScheduleDto> teachingClassPage = teachingClassService.getTeachingClassSchedule(page, taskId, classIds, null);
        List<TeachingClassWeekScheduleDto> resultList = teachingClassPage.getList();

        //根据最大周次生成课表模板
        int periods = basicRuleService.getMaxPeriodScheme(taskId, taskInfo.getSchoolId(), taskInfo.getTerm()).getPeriodSchemes().size();
        String title = "{} 教学班课表  \n  {}";
        writer.merge(7, StrUtil.format(title, teachingClass.getTeachingClassName(), taskInfo.getTermName()), false);
        writer.setRowHeight(0, 40);
        long courseNum = resultList.stream().filter(o -> CollUtil.isNotEmpty(o.getSchedules())).map(TeachingClassWeekScheduleDto::getCourseId).distinct().count();
        long sectionNum = resultList.stream()
                .flatMap(studentTeachingClass -> studentTeachingClass.getSchedules().stream())
                .filter(schedule -> ObjUtil.isNotNull(schedule.getTimeCode())).count();
        String filterTem = "共: {}门课程，{}节课   导出时间:{} ";
        String filter = StrUtil.format(filterTem, courseNum, sectionNum, DateUtil.now());
        writer.merge(7, filter, false);
        List<List<String>> rows = ExcelFormatUtil.getScheduleFormat(periods, 7);
        for (TeachingClassWeekScheduleDto item : resultList) {
            //以及排好的课节
            List<ScheduleDto> arrangeSchedule = item.getSchedules().stream().filter(scheduleDto -> StrUtil.isNotBlank(scheduleDto.getTimeCode())).collect(Collectors.toList());
            //根据授课类型分组 使用TreeMap来排序
            TreeMap<Integer, List<ScheduleDto>> mapByHourType = arrangeSchedule.stream()
                    .collect(Collectors.groupingBy(ScheduleDto::getHourType, TreeMap::new, Collectors.toList()));
            mapByHourType.forEach((hourType, byHourTypeList) -> {
                //根据timeCode分组
                byHourTypeList.stream().collect(Collectors.groupingBy(ScheduleDto::getTimeCode)).forEach((timeCode, byTimeCodeList) -> {
                    //根据week分组
                    byTimeCodeList.stream().collect(Collectors.groupingBy(ScheduleDto::getWeek)).forEach((week, byWeekList) -> {
                        //单个教学班 单个讲授类型 单个周次  单个节次 对应字符串
//                            String scheduleHour = "{courseName}({hourType}) \n{teachingClassName}\n{buildingName}{roomName}\n{week}"
                        String scheduleHour = "{}({}) \n{}\n{}\n{}{}\n{}";
                        //key 0101  节次
                        int index = Integer.parseInt(timeCode.substring(2, 4));
                        String buildingName = byWeekList.get(0).getBuildingName();
                        String roomName = byWeekList.get(0).getRoomName();
                        String weekString = StrUtil.format("[{}]周", WeekUtil.binaryToString(week));
                        String teacherNames = ExcelFormatUtil.getTeacherName(item.getTeachers());

                        String format = StrUtil.format(scheduleHour, item.getCourseName(), Objects.requireNonNull(HourType.getByCode(hourType)).getMsg(),
                                item.getTeachingClassName(), teacherNames,buildingName, roomName, weekString);
                        rows.get(index).set(GlobalConstant.dayCode.indexOf(timeCode.substring(0, 2)) + 1, format);
                    });
                });
            });
        }
        writer.write(rows, false);
        setExcelForm(writer, rows, 2);
        writer.close();
        return GlobalConstant.ACCESS_PATH + "/static/OutputExcel" + storePath;
    }

    /**
     * 格式化
     *
     * @param writer
     * @param rows
     * @param headLine 表头行数
     */
    private void setExcelForm(ExcelWriter writer, List<List<String>> rows, Integer headLine) {
        int start = 0;
        int end = start + 1;
        writer.setColumnWidth(0, 10);
        for (int colIndex = 1; colIndex < rows.get(0).size(); colIndex++) {
            writer.setColumnWidth(colIndex, 20);
            for (int i = 0; i <= rows.size() + 1; i++) {
                if (i < headLine) {
                    writer.setRowHeight(i, 30);
                } else {
                    writer.setRowHeight(i, 45);
                }
            }
            while (start < rows.size()) {
                if (!"--".equals(rows.get(start).get(colIndex))
                        && end < rows.size()
                        && rows.get(start).get(colIndex).equals(rows.get(end).get(colIndex))) {
                    end++;
                } else {
                    if (end - start > 1) {
                        writer.merge(start + headLine, end + headLine - 1, colIndex, colIndex, rows.get(start).get(colIndex), false);
                    }
                    start = end;
                    end = start + 1;
                }
            }
            start = 0;
            end = start + 1;
        }
    }


    @Override
    public String summaryScheduleToExcel(Integer taskId, Integer scheduleType) throws IOException {
        TaskInfo taskInfo = taskInfoService.getById(taskId);
        String name = "/全校总表-";
        //1:教室 2:教师 3:行政班 4:教学班
        switch (scheduleType) {
            case 1:
                name = "/全校教室总表-";
                break;
            case 2:
                name = "/全校教师总表-";
                break;
            case 3:
                name = "/全校行政班总表-";
                break;
            case 4:
                name = "/全校教学班总表-";
                break;
        }
        String storePath = "/" + taskInfo.getTaskName() + name + LocalDate.now() + ".xlsx";
        String targetPath = GlobalConstant.OUTPUT_EXCEL_PATH + storePath;

        FileUtil.del(targetPath);

        List<RuleWeekDay> weekDays = basicRuleService.getWeekDays(taskId, taskInfo.getSchoolId(), taskInfo.getTerm());
        weekDays.sort(Comparator.comparing(RuleWeekDay::getWeekDayCode));

        //记录该任务所有课时编码
        List<String> timeCodeString = new ArrayList<>();
        String msg = FixType.getByCode(scheduleType).getMsg();
        String header = msg.substring(0, msg.length() - 2);
        ExcelWriter writer = ExcelUtil.getWriter(targetPath, header + "总课表");
        //设置表头
        writer.merge(0, 2, 0, 0, header + "/课表", false);
        //记录下周开始的列值 总列值
        int firstCol = 1;
        /*
        基础平台 上午 1 中午4 下午2 晚上3
        */
        for (RuleWeekDay weekDay : weekDays) {
            weekDay.getPeriodSchemes().forEach(o -> {
                switch (o.getPeriodType()){
                    case 1 : o.setSorted(1);
                        break;
                    case 2 : o.setSorted(3);
                        break;
                    case 3 : o.setSorted(4);
                        break;
                    case 4 : o.setSorted(2);
                        break;
                }
            });
            weekDay.getPeriodSchemes().sort(Comparator.comparing(PeriodScheme::getSorted));
            int amNum = 0;
            int lunch = 0;
            int pmNum = 0;
            int night = 0;
            //记录下上午下午的列值 用于合并单元格 以及写入节次
            for (PeriodScheme periodScheme : weekDay.getPeriodSchemes()) {
                if (periodScheme.getPeriodType() == 1) {
                    amNum++;
                    writer.writeCellValue(firstCol + amNum - 1, 2, periodScheme.getPeriodName());
                } else if (periodScheme.getPeriodType() == 4) {
                    lunch++;
                    writer.writeCellValue(firstCol + amNum + lunch - 1, 2, periodScheme.getPeriodName());
                }else if (periodScheme.getPeriodType() == 2) {
                    pmNum++;
                    writer.writeCellValue(firstCol + amNum + lunch + pmNum - 1, 2, periodScheme.getPeriodName());
                }else if (periodScheme.getPeriodType() == 3) {
                    night++;
                    writer.writeCellValue(firstCol + amNum + lunch + pmNum + night - 1, 2, periodScheme.getPeriodName());
                }
                timeCodeString.add(weekDay.getWeekDayCode() + String.format("%02d", periodScheme.getPeriod()));
            }
            //写入上午下午
            if (amNum == 1) {
                writer.writeCellValue(firstCol, 1, "上午");
            } else if (amNum > 1) {
                writer.merge(1, 1, firstCol, firstCol + amNum - 1, "上午", false);
            }
            if (lunch == 1) {
                writer.writeCellValue(firstCol + amNum, 1, "中午");
            } else if (lunch > 1) {
                writer.merge(1, 1, firstCol + amNum, firstCol + amNum + lunch - 1, "中午", false);
            }
            if (pmNum == 1) {
                writer.writeCellValue(firstCol + amNum + lunch, 1, "下午");
            } else if (pmNum > 1) {
                writer.merge(1, 1, firstCol + amNum + lunch, firstCol + amNum + lunch + pmNum - 1, "下午", false);
            }
            if (night == 1) {
                writer.writeCellValue(firstCol + amNum + lunch + pmNum, 1, "晚上");
            } else if (night > 1) {
                writer.merge(1, 1, firstCol + amNum + lunch + pmNum, firstCol + amNum + lunch + pmNum + night - 1, "晚上", false);
            }

            //写入星期
            if (amNum + lunch + pmNum + night == 1) {
                writer.writeCellValue(firstCol, 0, GlobalConstant.dayNameCodeMap.get(weekDay.getWeekDayCode()));
            } else {
                writer.merge(0, 0, firstCol, firstCol + amNum + lunch + pmNum + night - 1, GlobalConstant.dayNameCodeMap.get(weekDay.getWeekDayCode()), false);
            }
            firstCol = firstCol + amNum + lunch + pmNum + night;
        }

        writer.setColumnWidth(-1, 30);
        writer.passRows(3);
        //1:教室 2:教师 3:行政班 4:教学班
        if (scheduleType == FixType.Class.getCode()) {
            fillClassSummarySchedule(taskId, timeCodeString, writer);
        } else if (scheduleType == FixType.Teacher.getCode()) {
            fillTeacherSummarySchedule(taskId, timeCodeString, writer);
        } else if (scheduleType == FixType.Room.getCode()) {
            fillRoomSummarySchedule(taskId, timeCodeString, writer);
        } else if (scheduleType == FixType.TeachingClass.getCode()) {
            fillTeachingClassSummarySchedule(taskId, timeCodeString, writer);
        }
        writer.setDefaultRowHeight(60);
        writer.setRowHeight(0, 30);
        writer.setRowHeight(1, 30);
        writer.setRowHeight(2, 30);

//        writer.flush(new File(targetPath));
        writer.close();
        return GlobalConstant.ACCESS_PATH + "/static/OutputExcel/" + storePath;
    }

    public void fillClassSummarySchedule(Integer taskId, List<String> timeCodeString, ExcelWriter writer) {
        //教学班 及对应课表
        List<ScheduleDto> teachingClassSchedule = scheduleMapper.getScheduleByTeachingClassIds(taskId, null, null);
        List<Long> teachingClassIds = teachingClassSchedule.stream().map(ScheduleDto::getTeachingClassId).distinct().collect(Collectors.toList());
        //根据行政班对课表进行分组
        Map<String, List<ScheduleDto>> scheduleClassMap = new HashMap<>();
        for (ScheduleDto schedule : teachingClassSchedule) {
            String[] singleClass = schedule.getToClass().split(",");
            for (String single : singleClass) {
                if (StrUtil.isNotBlank(single)) {
                    scheduleClassMap.computeIfAbsent(single.trim(), k -> new ArrayList<>()).add(schedule);
                }
            }
        }
        //老师
        Map<Long, List<Teacher>> teachingClassToTeacher = teacherService.getTeacherByTeachingClassIds(teachingClassIds).stream()
                .collect(Collectors.groupingBy(Teacher::getTeachingClassId));
        //获取行政班
        List<ClassInfo> classList = classInfoMapper.selectList(new LambdaQueryWrapper<ClassInfo>()
                .eq(ClassInfo::getTaskId, taskId));
        classList = classList.stream().sorted(Comparator.comparing(ClassInfo::getClassName)).collect(Collectors.toList());
        for (ClassInfo classDto : classList) {
            List<String> row = Arrays.asList(new String[timeCodeString.size() + 1]);
            //首列  设置行政班名称
            row.set(0, classDto.getClassName());

            List<ScheduleDto> scheduleList = scheduleClassMap.get(String.valueOf(classDto.getId()));
            if (scheduleList == null) {
                writer.writeRow(row);
                continue;
            }
            scheduleList.stream().collect(Collectors.groupingBy(ScheduleDto::getTimeCode))
                    .forEach((timeCode, byTimeCodeList) -> {
                        //单节课数据
                        StringJoiner singleSchedule = new StringJoiner("\n");
                        for (ScheduleDto allScheduleDto : byTimeCodeList) {
                            //单个教学班数据 {courseName}{单双}\n{teachName}\n{buildingName}{roomName}
                            String singleScheduleTemplate = "{} \n {} \n {} \n {} {} \n {}";
                            String teachingClassName = allScheduleDto.getTeachingClassName();
                            String courseName = allScheduleDto.getCourseName();
                            //多教师版本
                            List<Teacher> teacher = teachingClassToTeacher.getOrDefault(allScheduleDto.getTeachingClassId(), new ArrayList<>());
                            teacher = teacher.stream().filter(o -> Objects.equals(allScheduleDto.getHourType(), o.getTeacherType())).collect(Collectors.toList());
                            String teachName = teacher.stream().map(Teacher::getTeacherName).collect(Collectors.joining(","));
                            String weekString = StrUtil.format("[{}]周", WeekUtil.binaryToString(allScheduleDto.getWeek()));
                            String buildingName = allScheduleDto.getBuildingName();
                            String roomName = allScheduleDto.getRoomName();
                            singleSchedule.add(StrUtil.format(singleScheduleTemplate,
                                    courseName, teachingClassName, teachName, buildingName, roomName, weekString));
                        }
                        row.set(timeCodeString.indexOf(timeCode) + 1, singleSchedule.toString());
                    });
            writer.writeRow(row);
        }
    }

    public void fillTeacherSummarySchedule(Integer taskId, List<String> timeCodeString, ExcelWriter writer) {
        //教学班 及对应课表
        List<ScheduleDto> teachingClassSchedule = scheduleMapper.getScheduleByTeachingClassIds(taskId, null, null);
        if (CollUtil.isEmpty(teachingClassSchedule)) {
            return;
        }
        List<Long> teachingClassIds = teachingClassSchedule.stream()
                .map(ScheduleDto::getTeachingClassId).distinct().collect(Collectors.toList());

        //老师
        List<Teacher> teacherByTeachingClassIds = teacherService.getTeacherByTeachingClassIds(teachingClassIds);
        Map<Long, List<Teacher>> teachingClassToTeacher = teacherByTeachingClassIds.stream()
                .collect(Collectors.groupingBy(Teacher::getTeachingClassId));

        //获取行政班
        Map<Long, String> classMap = classInfoMapper.selectList(new LambdaQueryWrapper<ClassInfo>()
                        .eq(ClassInfo::getTaskId, taskId))
                .stream().collect(Collectors.toMap(ClassInfo::getId, ClassInfo::getClassName));

        //确定每节课表所对应的教师。 遍历课表 分组
        Map<String, List<ScheduleDto>> scheduleTeacherMap = new HashMap<>();
        for (ScheduleDto schedule : teachingClassSchedule) {
            List<Teacher> teachers = teachingClassToTeacher.getOrDefault(schedule.getTeachingClassId(), new ArrayList<>());
            teachers.stream().filter(t -> Objects.equals(t.getTeacherType(), schedule.getHourType()))
                    .forEach(teacher -> {
                scheduleTeacherMap.computeIfAbsent(teacher.getTeacherName() + teacher.getBaseTeacherId(),
                        k -> new ArrayList<>()).add(schedule);
            });
        }
        //遍历分组 生成excel
        for (Map.Entry<String, List<ScheduleDto>> entry : scheduleTeacherMap.entrySet()) {
            List<ScheduleDto> scheduleList = entry.getValue();
            if (CollUtil.isEmpty(scheduleList)) {
                continue;
            }
            List<String> row = Arrays.asList(new String[timeCodeString.size() + 1]);
            //首列  设置行政班名称
            row.set(0, entry.getKey());
            scheduleList.stream().collect(Collectors.groupingBy(ScheduleDto::getTimeCode))
                    .forEach((timeCode, byTimeCodeList) -> {
                        //单节课数据
                        StringJoiner singleSchedule = new StringJoiner("\n");
                        for (ScheduleDto allScheduleDto : byTimeCodeList) {
                            //单个教学班数据 {courseName}{单双}\n{行政班名}\n{buildingName}{roomName}
                            String singleScheduleTemplate = "{} \n {} \n {}{} \n {}";
                            String courseName = allScheduleDto.getCourseName();
                            //多个行政班情况
                            StringJoiner className = new StringJoiner(",");
                            String toClass = allScheduleDto.getToClass();
                            if (StrUtil.isNotEmpty(toClass)){
                                for (String s : allScheduleDto.getToClass().split(",")) {
                                    if (StrUtil.isNotBlank(classMap.get(Long.valueOf(s)))) {
                                        className.add(classMap.get(Long.valueOf(s)));
                                    }
                                }
                            }
                            String weekString = StrUtil.format("[{}]周", WeekUtil.binaryToString(allScheduleDto.getWeek()));
                            String buildingName = allScheduleDto.getBuildingName();
                            String roomName = allScheduleDto.getRoomName();
                            singleSchedule.add(StrUtil.format(singleScheduleTemplate,
                                    courseName, className.toString(), buildingName, roomName, weekString));
                        }
                        row.set(timeCodeString.indexOf(timeCode) + 1, singleSchedule.toString());
                    });
            writer.writeRow(row);
        }



        //没课的教师
        TaskInfo taskInfo = taskInfoService.getById(taskId);
        List<Teacher> teacherList = teacherService.lambdaQuery()
                .eq(Teacher::getSchoolId, taskInfo.getSchoolId())
                .eq(Teacher::getTerm, taskInfo.getTerm())
                .eq(Teacher::getDeleted, Deleted.NOT.getCode()).list();
        List<Long> teacherIds = teacherByTeachingClassIds.stream()
                .map(Teacher::getTeacherId).collect(Collectors.toList());
        teacherList = teacherList.stream().filter(o -> !teacherIds.contains(o.getTeacherId())).collect(Collectors.toList());
        for (Teacher teacher : teacherList) {
            List<String> row = Arrays.asList(new String[timeCodeString.size() + 1]);
            //首列  设置行政班名称
            row.set(0, teacher.getTeacherName() + teacher.getBaseTeacherId());
            writer.writeRow(row);
        }


    }

    public void fillRoomSummarySchedule(Integer taskId, List<String> timeCodeString, ExcelWriter writer) {
        //教学班 及对应课表
        List<ScheduleDto> teachingClassSchedule = scheduleMapper.getScheduleByTeachingClassIds(taskId, null, null);
        if (CollUtil.isEmpty(teachingClassSchedule)) {
            return;
        }
        List<Long> teachingClassIds = teachingClassSchedule.stream().map(ScheduleDto::getTeachingClassId).distinct().collect(Collectors.toList());

        //老师
        Map<Long, List<Teacher>> teachingClassToTeacher = teacherService.getTeacherByTeachingClassIds(teachingClassIds).stream()
                .collect(Collectors.groupingBy(Teacher::getTeachingClassId));

        //获取行政班
        Map<Long, String> classMap = classInfoMapper.selectList(new LambdaQueryWrapper<ClassInfo>()
                        .eq(ClassInfo::getTaskId, taskId))
                .stream().collect(Collectors.toMap(ClassInfo::getId, ClassInfo::getClassName));
        //根据room分组
        Map<Long, List<ScheduleDto>> scheduleRoomMap = teachingClassSchedule.stream()
                .collect(Collectors.groupingBy(ScheduleDto::getRoomId));

        //遍历分组 生成excel
        for (Map.Entry<Long, List<ScheduleDto>> entry : scheduleRoomMap.entrySet()) {
            List<ScheduleDto> scheduleList = entry.getValue();
            if (CollUtil.isEmpty(scheduleList)) {
                continue;
            }
            List<String> row = Arrays.asList(new String[timeCodeString.size() + 1]);
            //首列  设置行政班名称
            row.set(0, scheduleList.get(0).getBuildingName() + scheduleList.get(0).getRoomName());
            scheduleList.stream().collect(Collectors.groupingBy(ScheduleDto::getTimeCode))
                    .forEach((timeCode, byTimeCodeList) -> {
                        //单节课数据
                        StringJoiner singleSchedule = new StringJoiner("\n");
                        for (ScheduleDto allScheduleDto : byTimeCodeList) {
                            //单个教学班数据 {courseName}{单双}\n{行政班名}\n{teacherName}
                            String singleScheduleTemplate = "{} \n {} \n {} \n {}";
                            String courseName = allScheduleDto.getCourseName();
                            //多个行政班情况
                            StringJoiner className = new StringJoiner(",");
                            String toClass = allScheduleDto.getToClass();
                            if (StrUtil.isNotEmpty(toClass)){
                                for (String s : allScheduleDto.getToClass().split(",")) {
                                    if (StrUtil.isNotBlank(classMap.get(Long.valueOf(s)))) {
                                        className.add(classMap.get(Long.valueOf(s)));
                                    }
                                }
                            }
                            //多教师版本
                            List<Teacher> teacher = teachingClassToTeacher.getOrDefault(allScheduleDto.getTeachingClassId(), new ArrayList<>());
                            teacher = teacher.stream().filter(o -> Objects.equals(allScheduleDto.getHourType(), o.getTeacherType())).collect(Collectors.toList());
                            String teachName = teacher.stream().map(Teacher::getTeacherName).collect(Collectors.joining(","));
                            String weekString = StrUtil.format("[{}]周", WeekUtil.binaryToString(allScheduleDto.getWeek()));
                            singleSchedule.add(StrUtil.format(singleScheduleTemplate,
                                    courseName, className.toString(), teachName, weekString));
                        }
                        row.set(timeCodeString.indexOf(timeCode) + 1, singleSchedule.toString());
                    });
            writer.writeRow(row);
        }



        //没课的教室
        TaskInfo taskInfo = taskInfoService.getById(taskId);
        List<Room> roomList = roomMapper.selectList(new LambdaQueryWrapper<Room>()
                .eq(Room::getSchoolId, taskInfo.getSchoolId())
                .eq(Room::getTerm, taskInfo.getTerm())
                .eq(Room::getDeleted, Deleted.NOT.getCode()));
        List<Long> roomIds = teachingClassSchedule.stream()
                .map(ScheduleDto::getRoomId).collect(Collectors.toList());
        roomList = roomList.stream().filter(o -> !roomIds.contains(o.getRoomId())).collect(Collectors.toList());
        for (Room room : roomList) {
            List<String> row = Arrays.asList(new String[timeCodeString.size() + 1]);
            //首列  设置行政班名称
            row.set(0, room.getBuildingName() + room.getRoomName());
            writer.writeRow(row);
        }



    }

    public void fillTeachingClassSummarySchedule(Integer taskId, List<String> timeCodeString, ExcelWriter writer) {
        //教学班 及对应课表
        List<ScheduleDto> teachingClassSchedule = scheduleMapper.getScheduleByTeachingClassIds(taskId, null, null);
        if (CollUtil.isEmpty(teachingClassSchedule)) {
            return;
        }
        List<Long> teachingClassIds = teachingClassSchedule.stream().map(ScheduleDto::getTeachingClassId).distinct().collect(Collectors.toList());

        //老师
        Map<Long, List<Teacher>> teachingClassToTeacher = teacherService.getTeacherByTeachingClassIds(teachingClassIds).stream()
                .collect(Collectors.groupingBy(Teacher::getTeachingClassId));

        //获取行政班
        Map<Long, String> classMap = classInfoMapper.selectList(new LambdaQueryWrapper<ClassInfo>()
                        .eq(ClassInfo::getTaskId, taskId))
                .stream().collect(Collectors.toMap(ClassInfo::getId, ClassInfo::getClassName));

        //根据教学班分组
        Map<Long, List<ScheduleDto>> scheduleTeachingClassMap = teachingClassSchedule.stream()
                .collect(Collectors.groupingBy(ScheduleDto::getTeachingClassId));
        List<Map.Entry<Long, List<ScheduleDto>>> sortKeySet = scheduleTeachingClassMap.entrySet().stream().sorted(Comparator.comparing(Map.Entry::getKey)).collect(Collectors.toList());

        //遍历分组 生成excel
        for (Map.Entry<Long, List<ScheduleDto>> entry : sortKeySet) {
            List<ScheduleDto> scheduleList = entry.getValue();
            if (CollUtil.isEmpty(scheduleList)) {
                continue;
            }
            List<String> row = Arrays.asList(new String[timeCodeString.size() + 1]);
            //首列  设置教学班名称
            row.set(0, scheduleList.get(0).getTeachingClassName());
            scheduleList.stream().collect(Collectors.groupingBy(ScheduleDto::getTimeCode))
                    .forEach((timeCode, byTimeCodeList) -> {
                        //单节课数据
                        StringJoiner singleSchedule = new StringJoiner("\n");
                        for (ScheduleDto allScheduleDto : byTimeCodeList) {
                            //单个教学班数据 {courseName}{单双}\n{行政班名}\n{teacherName}
                            String singleScheduleTemplate = "{} \n {} \n {} \n {}{} \n {}";
                            String courseName = allScheduleDto.getCourseName();
                            //多个行政班情况
                            StringJoiner className = new StringJoiner(",");
                            String toClass = allScheduleDto.getToClass();
                            if (StrUtil.isNotEmpty(toClass)){
                                for (String s : allScheduleDto.getToClass().split(",")) {
                                    if (StrUtil.isNotBlank(classMap.get(Long.valueOf(s)))) {
                                        className.add(classMap.get(Long.valueOf(s)));
                                    }
                                }
                            }
                            //多教师版本
                            List<Teacher> teacher = teachingClassToTeacher.getOrDefault(allScheduleDto.getTeachingClassId(), new ArrayList<>());
                            teacher = teacher.stream().filter(o -> Objects.equals(allScheduleDto.getHourType(), o.getTeacherType())).collect(Collectors.toList());
                            String teachName = teacher.stream().map(Teacher::getTeacherName).collect(Collectors.joining(","));

                            String weekString = StrUtil.format("[{}]周", WeekUtil.binaryToString(allScheduleDto.getWeek()));
                            String buildingName = allScheduleDto.getBuildingName();
                            String roomName = allScheduleDto.getRoomName();
                            singleSchedule.add(StrUtil.format(singleScheduleTemplate,
                                    courseName, className.toString(), teachName, buildingName, roomName, weekString));
                        }
                        row.set(timeCodeString.indexOf(timeCode) + 1, singleSchedule.toString());
                    });
            writer.writeRow(row);
        }



        //没课的教学班
        List<TeachingClass> teachingClassList = teachingClassService.lambdaQuery()
                .eq(TeachingClass::getTaskId,taskId)
                .eq(TeachingClass::getDeleted, Deleted.NOT.getCode()).list();
        List<Long> tcIds = teachingClassSchedule.stream()
                .map(ScheduleDto::getTeachingClassId).collect(Collectors.toList());
        teachingClassList = teachingClassList.stream().filter(o -> !tcIds.contains(o.getTeachingClassId())).collect(Collectors.toList());
        for (TeachingClass teachingClass : teachingClassList) {
            List<String> row = Arrays.asList(new String[timeCodeString.size() + 1]);
            //首列  设置行政班名称
            row.set(0, teachingClass.getTeachingClassName());
            writer.writeRow(row);
        }



    }


    @Override
    public String allScheduleToExcel(Integer taskId) {
        String modelPath = GlobalConstant.MODEL_EXCEL_PATH + "【模板】课程表信息.xls";

        TaskInfo taskInfo = taskInfoService.getById(taskId);
        String storePath = "/" + taskInfo.getTaskName() + "/syncScheduleToBasic.xlsx";
        String targetPath = GlobalConstant.OUTPUT_EXCEL_PATH + storePath;

        FileUtil.copy(modelPath, targetPath, true);
        ExcelWriter writer = ExcelUtil.getWriter(targetPath);
        writer.setSheet(0);
        writer.passCurrentRow();
        writer.passCurrentRow();

        List<SyncScheduleDto> syncScheduleDtos = scheduleMapper.syncScheduleDto(taskId);
        //老师
        List<Long> teachingClassIds = syncScheduleDtos.stream().map(SyncScheduleDto::getTeachingClassId).distinct().collect(Collectors.toList());
//        Map<Long, String> teachingClassToTeacher = teacherService.getTeacherByTeachingClassIds(teachingClassIds).stream()
//                .collect(Collectors.groupingBy(Teacher::getTeachingClassId,
//                        Collectors.collectingAndThen(
//                                Collectors.mapping(Teacher::getBaseTeacherId, Collectors.toList()),
//                                teachers -> teachers.size() > 0 ? teachers.get(0) : null)));

        //多教师
        Map<Long, List<Teacher>> teachingClassToTeacher = teacherService.getTeacherByTeachingClassIds(teachingClassIds).stream()
                .collect(Collectors.groupingBy(Teacher::getTeachingClassId));

        //课时方案
        Map<String, String> daySchemeMap = ruleWeekDayService.lambdaQuery().eq(RuleWeekDay::getTaskId, taskId)
                .eq(RuleWeekDay::getDeleted, Deleted.NOT.getCode()).list().stream()
                .collect(Collectors.toMap(RuleWeekDay::getWeekDayCode, RuleWeekDay::getBaseSchemeName));
        List<List<String>> rows = new LinkedList<>();
        List<String> row = null;
        String roomType = "";
        for (SyncScheduleDto syncScheduleDto : syncScheduleDtos) {
            if (ObjUtil.isNull(syncScheduleDto.getTimeCode()) || ObjUtil.isNull(syncScheduleDto.getCourseName())) {
                continue;
            }
            row = new LinkedList<>();
            row.add("全部");
            //上课周数
            String weekNum = IntStream.range(0, syncScheduleDto.getWeek().length())
                    .filter(i -> syncScheduleDto.getWeek().charAt(i) == '1')
                    .mapToObj(i -> String.valueOf(i + 1))
                    .collect(Collectors.joining(","));
            row.add(weekNum);
            //星期
            String week = syncScheduleDto.getTimeCode().substring(0, 2);
            row.add(GlobalConstant.dayNameCodeMap.get(week));
            //课时序号
            row.add(String.valueOf(Integer.parseInt(syncScheduleDto.getTimeCode().substring(2))));
            //教室类型大类1,2,3下的，转换为大类上传
            if ("123".contains(syncScheduleDto.getRoomType().toString().substring(0, 1))) {
                roomType = syncScheduleDto.getRoomType().toString().substring(0, 1);
            }
            row.add(StrUtil.isBlank(roomType) ? syncScheduleDto.getRoomType().toString() : roomType);
            row.add(syncScheduleDto.getRoomName());
            row.add(syncScheduleDto.getCourseName());
            row.add(syncScheduleDto.getTeachingClassName());
            //教师id
            //多教师版本
            String teacherId = "";
            teacherId = teachingClassToTeacher.getOrDefault(syncScheduleDto.getTeachingClassId(), new ArrayList<>())
                    .stream().filter(o -> Objects.equals(o.getTeacherType(), syncScheduleDto.getHourType()))
                    .map(Teacher::getBaseTeacherId).distinct().collect(Collectors.joining(","));
            row.add(teacherId);
//            row.add(teachingClassToTeacher.get(syncScheduleDto.getTeachingClassId()));
            row.add("");
            row.add(daySchemeMap.get(week));
            row.add(GlobalConstant.hourTypeMap.get(syncScheduleDto.getHourType()));
            rows.add(row);
        }
        writer.write(rows, false);
        writer.close();
        return GlobalConstant.ACCESS_PATH + "/static/OutputExcel/" + storePath;
    }

    @Override
    public int[] classStatistics(Integer taskId, String schoolId, String term) {
        List<TeachingClassWeek> weeks = teachingClassWeekMapper.classStatistics(taskId);
        int all = weeks.size();
        long count = weeks.stream().filter(o -> o.getIsLocked() == 2).count();
        return new int[]{all, (int) count};
    }

    @Override
    public String segmentToExcel(Integer taskId, String gradeId, String majorId, String courseTypeId, String keyword) {
        TaskInfo taskInfo = taskInfoService.getById(taskId);
        String storePath = "/" + taskInfo.getTaskName() + "/环节课表编排-" + LocalDate.now() + ".xlsx";
        String targetPath = GlobalConstant.OUTPUT_EXCEL_PATH + storePath;

        FileUtil.del(targetPath);
        ExcelWriter writer = ExcelUtil.getWriter(targetPath);

        Page<TeachingClassSegmentDto> page = new Page<>(1, -1);
        PageInfo<TeachingClassSegmentDto> teachingClassPage = this.getTeachingClassSegmentPage(taskId, page, gradeId, majorId, courseTypeId, keyword);
        List<TeachingClassSegmentDto> resultList = teachingClassPage.getList();
        String title = "{} 课表编排(环节)  \n  {}";
        writer.merge(7, StrUtil.format(title, taskInfo.getSchoolName(), taskInfo.getTermName()), false);
        writer.setRowHeight(0, 40);
        String filterTem = "共: {}个教学班   导出时间:{} ";
        String filter = StrUtil.format(filterTem, resultList.size(), DateUtil.now());
        writer.merge(7, filter, false);
        List<List<String>> rows = new ArrayList<>();
        rows.add(Arrays.asList("编号", "环节名称", "教师", "周次", "班级名称", "专业", "年级", "教学班名称"));
//        rows.add(Arrays.asList("环节名称", "教师", "周次", "班级名称", "专业", "年级", "教学班名称"));
        List<String> row;
        for (TeachingClassSegmentDto item : resultList) {
            //任课教师名称
            String teacherName = ExcelFormatUtil.getTeacherName(item.getTeachers());
            //周次
            String weeks = ExcelFormatUtil.getWeekString(item.getCourseWeeks());
            row = Arrays.asList(
//                    item.getTeachingClassId().toString(),
                    item.getSegmentName(),
                    teacherName,
                    weeks.split(":")[0],
                    item.getClassInfos().stream().map(ClassInfo::getClassName).collect(Collectors.joining(",")),
                    item.getMajorName(),
                    item.getGradeName(),
                    item.getTeachingClassName());
            rows.add(row);
        }
        writer.write(rows, false);
        ExcelFormatUtil.setFont(writer);
        writer.close();
        return GlobalConstant.ACCESS_PATH + "/static/OutputExcel/" + storePath;
    }

    @Override
    public List<TeachingClassWeekScheduleDto> getScheduleByClassId(Integer taskId, Long studentId, List<Long> classIds) {
        List<TeachingClassStudent> teachingClassStudents = teachingClassStudentMapper.selectList(new LambdaQueryWrapper<TeachingClassStudent>()
                .eq(TeachingClassStudent::getStudentId, studentId)
                .eq(TeachingClassStudent::getFlag, 1).eq(TeachingClassStudent::getDeleted, Deleted.NOT.getCode()));


        List<Long> teachingClassIds = teachingClassStudents.stream().map(TeachingClassStudent::getTeachingClassId)
                .distinct().collect(Collectors.toList());

        if (CollUtil.isNotEmpty(classIds)) {
            teachingClassIds.addAll(classIds);
        }

        List<Long> collect = teachingClassIds.stream().distinct().collect(Collectors.toList());
        Page<TeachingClassWeekScheduleDto> page = new Page<>(1, -1);
        PageInfo<TeachingClassWeekScheduleDto> teachingClassPage =
                teachingClassService.getTeachingClassAllSchedule(page, taskId, collect);

        return teachingClassPage.getList();
    }

    @Override
    public List<Student> checkByStudentIdBatch(Integer taskId, CheckByStudentIdBatchDTO checkByStudentIdBatchDTO) {
        List<Long> studentIds = checkByStudentIdBatchDTO.getStudentIds();

        List<Long> conflictStudentIds = new ArrayList<>();
        if(CollUtil.isNotEmpty(studentIds)){

            studentIds.forEach(o->{
                CheckByStudentIdDTO checkByStudentIdDTO = new CheckByStudentIdDTO();
                checkByStudentIdDTO.setSelectTeachingClassId(checkByStudentIdBatchDTO.getSelectTeachingClassId());
                checkByStudentIdDTO.setStudentId(o);
                Boolean aBoolean = checkByStudentId(taskId, checkByStudentIdDTO);
                if(aBoolean){
                    conflictStudentIds.add(o);


                }
            });
        }
        List<Student> studentList = new ArrayList<>();
        if(CollUtil.isNotEmpty(conflictStudentIds)){
            studentList = studentService.lambdaQuery().eq(Student::getTaskId, taskId).in(Student::getStudentId, conflictStudentIds).list();
        }

        return studentList;
    }

    @Override
    public Boolean checkByStudentId(Integer taskId, CheckByStudentIdDTO checkByStudentIdDTO) {

        List<TeachingClassStudent> teachingClassStudents = teachingClassStudentMapper
                .selectList(new LambdaQueryWrapper<TeachingClassStudent>()
                .eq(TeachingClassStudent::getStudentId, checkByStudentIdDTO.getStudentId())
                .eq(TeachingClassStudent::getFlag, 1)
                .eq(TeachingClassStudent::getDeleted, Deleted.NOT.getCode()));

        List<Long> teachingClassIds = teachingClassStudents.stream().map(TeachingClassStudent::getTeachingClassId)
                .distinct().collect(Collectors.toList());


        HashMap<String,List<TeachingClassTimeCode>> teachingClassCode = new HashMap<>();
        redisUtil.hmget(getCacheKeys(taskId, null, 7, null)).forEach((key,value)->{
            teachingClassCode.put(String.valueOf(key),(List<TeachingClassTimeCode>) value);
        });

        if(CollUtil.isEmpty(teachingClassCode.get(String.valueOf(checkByStudentIdDTO.getSelectTeachingClassId())))){
            return false;
        }

        Set<String> timecodeList = new HashSet<>();
        teachingClassIds.forEach(o->{
            List<TeachingClassTimeCode> strings = teachingClassCode.get(String.valueOf(o));
            if(CollUtil.isNotEmpty(strings)){
                strings.forEach(s->{
                    timecodeList.add(s.getTimeCode());
                });
            }
        });

        List<String> strings = teachingClassCode.get(String.valueOf(checkByStudentIdDTO.getSelectTeachingClassId()))
                .stream().map(TeachingClassTimeCode::getTimeCode).distinct().collect(Collectors.toList());

        List<String> conflct = new ArrayList<>();
        strings.forEach(o->{
            if(timecodeList.contains(o)) {
                conflct.add(o);
            }
        });
        if(CollUtil.isNotEmpty(checkByStudentIdDTO.getTeachingClassIds())){
            List<Long> teachingClassIds1 = checkByStudentIdDTO.getTeachingClassIds();
            TeachingClassTimeCode teachingClassTimeCode = teachingClassCode.get(String.valueOf(checkByStudentIdDTO.getSelectTeachingClassId())).get(0);
            teachingClassIds1.forEach(o->{
                List<TeachingClassTimeCode> teachingClassTimeCodes = teachingClassCode.get(String.valueOf(o));
                teachingClassTimeCodes.forEach(t->{
                    if(!t.getCourseId().equals(teachingClassTimeCode.getCourseId())){
                       if(strings.contains(t.getTimeCode())){
                           conflct.add(t.getTimeCode());
                       }
                    }
                });
            });
        }

        return CollUtil.isNotEmpty(conflct);

    }

    @Override
    public List<ArrangeTeachingClassRuleDto> removeProhibitFromCourse(Integer taskId, String schoolId, String termId, List<ArrangeTeachingClassRuleDto> teachingClassRuleList) {
        Set<String> timeProhibit;
        RuleUsable timeRule = ruleUsableService.getByCode(taskId, 12);
        if ("b".equals(timeRule.getOption())) {
            timeProhibit = basicRuleService.getTimeProhibit(taskId, schoolId, termId)
                    .stream().map(RuleTimeProhibit::getTimeCode).collect(Collectors.toSet());
        } else {
            timeProhibit = new HashSet<>();
        }
        return teachingClassRuleList.stream().filter(o -> !timeProhibit.contains(o.getTimeCode()))
                .collect(Collectors.toList());
    }


    public String getCacheKeys(Integer taskId, Long uniqueIdentify, int type, String standby) {
         /*
        返回值用StringBuilder 速度快
        1:存储教学班都有哪些学生  key->teachingClassId
        2:存储学生都选了哪些教学班，教学班详情  key->studentId
        3:存储教学班对应学生数据，然后同步到数据库
        4:学生可选教学班 key->studentId value -> Set<TeachingClassId>
        5:学生已选教学班
        6：教学班详情 包括课表 余量等
         */
        StringBuilder key = new StringBuilder();
        key.append(GlobalConstant.REDIS_PREFIX).append(taskId).append(StrUtil.C_COLON);
        switch (type) {
            case 1:
                return key.append("TeachingStudentId").append(StrUtil.C_COLON).append(uniqueIdentify).toString();
            case 2:
                return key.append("StudentTeachingClass").append(StrUtil.C_COLON).append(uniqueIdentify).toString();
            case 3:
                return key.append("TeachingClassStudent").toString();
            case 4:
                return key.append("StudentOptionalClass").append(StrUtil.C_COLON).append(uniqueIdentify).append(StrUtil.C_COLON).append(standby).toString();
            case 5:
                return key.append("StudentSelectedClass").append(StrUtil.C_COLON).append(uniqueIdentify).toString();
            case 6:
                return key.append("TeachingClassDetail").toString();
            case 7:
                return key.append("TeachingClassCode").toString();
            default:
                return "";
        }
    }
}